1 #include "mkvparser.hpp" 2 #include <cassert> 3 #include <cstring> 4 5 mkvparser::IMkvReader::~IMkvReader() 6 { 7 } 8 9 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) 10 { 11 assert(pReader); 12 assert(pos >= 0); 13 14 long long total, available; 15 16 long hr = pReader->Length(&total, &available); 17 assert(hr >= 0); 18 assert(pos < available); 19 assert((available - pos) >= 1); //assume here max u-int len is 8 20 21 unsigned char b; 22 23 hr = pReader->Read(pos, 1, &b); 24 if (hr < 0) 25 return hr; 26 27 assert(hr == 0L); 28 29 if (b & 0x80) //1000 0000 30 { 31 len = 1; 32 b &= 0x7F; //0111 1111 33 } 34 else if (b & 0x40) //0100 0000 35 { 36 len = 2; 37 b &= 0x3F; //0011 1111 38 } 39 else if (b & 0x20) //0010 0000 40 { 41 len = 3; 42 b &= 0x1F; //0001 1111 43 } 44 else if (b & 0x10) //0001 0000 45 { 46 len = 4; 47 b &= 0x0F; //0000 1111 48 } 49 else if (b & 0x08) //0000 1000 50 { 51 len = 5; 52 b &= 0x07; //0000 0111 53 } 54 else if (b & 0x04) //0000 0100 55 { 56 len = 6; 57 b &= 0x03; //0000 0011 58 } 59 else if (b & 0x02) //0000 0010 60 { 61 len = 7; 62 b &= 0x01; //0000 0001 63 } 64 else 65 { 66 assert(b & 0x01); //0000 0001 67 len = 8; 68 b = 0; //0000 0000 69 } 70 71 assert((available - pos) >= len); 72 73 long long result = b; 74 ++pos; 75 for (long i = 1; i < len; ++i) 76 { 77 hr = pReader->Read(pos, 1, &b); 78 79 if (hr < 0) 80 return hr; 81 82 assert(hr == 0L); 83 84 result <<= 8; 85 result |= b; 86 87 ++pos; 88 } 89 90 return result; 91 } 92 93 94 long long mkvparser::GetUIntLength( 95 IMkvReader* pReader, 96 long long pos, 97 long& len) 98 { 99 assert(pReader); 100 assert(pos >= 0); 101 102 long long total, available; 103 104 long hr = pReader->Length(&total, &available); 105 assert(hr >= 0); 106 assert(available <= total); 107 108 if (pos >= available) 109 return pos; //too few bytes available 110 111 unsigned char b; 112 113 hr = pReader->Read(pos, 1, &b); 114 115 if (hr < 0) 116 return hr; 117 118 assert(hr == 0L); 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 len = 1; 125 126 while (!(b & m)) 127 { 128 m >>= 1; 129 ++len; 130 } 131 132 return 0; //success 133 } 134 135 136 long long mkvparser::SyncReadUInt( 137 IMkvReader* pReader, 138 long long pos, 139 long long stop, 140 long& len) 141 { 142 assert(pReader); 143 144 if (pos >= stop) 145 return E_FILE_FORMAT_INVALID; 146 147 unsigned char b; 148 149 long hr = pReader->Read(pos, 1, &b); 150 151 if (hr < 0) 152 return hr; 153 154 if (hr != 0L) 155 return E_BUFFER_NOT_FULL; 156 157 if (b == 0) //we can't handle u-int values larger than 8 bytes 158 return E_FILE_FORMAT_INVALID; 159 160 unsigned char m = 0x80; 161 len = 1; 162 163 while (!(b & m)) 164 { 165 m >>= 1; 166 ++len; 167 } 168 169 if ((pos + len) > stop) 170 return E_FILE_FORMAT_INVALID; 171 172 long long result = b & (~m); 173 ++pos; 174 175 for (int i = 1; i < len; ++i) 176 { 177 hr = pReader->Read(pos, 1, &b); 178 179 if (hr < 0) 180 return hr; 181 182 if (hr != 0L) 183 return E_BUFFER_NOT_FULL; 184 185 result <<= 8; 186 result |= b; 187 188 ++pos; 189 } 190 191 return result; 192 } 193 194 195 long long mkvparser::UnserializeUInt( 196 IMkvReader* pReader, 197 long long pos, 198 long long size) 199 { 200 assert(pReader); 201 assert(pos >= 0); 202 assert(size > 0); 203 assert(size <= 8); 204 205 long long result = 0; 206 207 for (long long i = 0; i < size; ++i) 208 { 209 unsigned char b; 210 211 const long hr = pReader->Read(pos, 1, &b); 212 213 if (hr < 0) 214 return hr; 215 result <<= 8; 216 result |= b; 217 218 ++pos; 219 } 220 221 return result; 222 } 223 224 225 float mkvparser::Unserialize4Float( 226 IMkvReader* pReader, 227 long long pos) 228 { 229 assert(pReader); 230 assert(pos >= 0); 231 232 long long total, available; 233 234 long hr = pReader->Length(&total, &available); 235 assert(hr >= 0); 236 assert(available <= total); 237 assert((pos + 4) <= available); 238 239 float result; 240 241 unsigned char* const p = (unsigned char*)&result; 242 unsigned char* q = p + 4; 243 244 for (;;) 245 { 246 hr = pReader->Read(pos, 1, --q); 247 assert(hr == 0L); 248 249 if (q == p) 250 break; 251 252 ++pos; 253 } 254 255 return result; 256 } 257 258 259 double mkvparser::Unserialize8Double( 260 IMkvReader* pReader, 261 long long pos) 262 { 263 assert(pReader); 264 assert(pos >= 0); 265 266 double result; 267 268 unsigned char* const p = (unsigned char*)&result; 269 unsigned char* q = p + 8; 270 271 for (;;) 272 { 273 const long hr = pReader->Read(pos, 1, --q); 274 assert(hr == 0L); 275 276 if (q == p) 277 break; 278 279 ++pos; 280 } 281 282 return result; 283 } 284 285 signed char mkvparser::Unserialize1SInt( 286 IMkvReader* pReader, 287 long long pos) 288 { 289 assert(pReader); 290 assert(pos >= 0); 291 292 long long total, available; 293 294 long hr = pReader->Length(&total, &available); 295 assert(hr == 0); 296 assert(available <= total); 297 assert(pos < available); 298 299 signed char result; 300 301 hr = pReader->Read(pos, 1, (unsigned char*)&result); 302 assert(hr == 0); 303 304 return result; 305 } 306 307 short mkvparser::Unserialize2SInt( 308 IMkvReader* pReader, 309 long long pos) 310 { 311 assert(pReader); 312 assert(pos >= 0); 313 314 long long total, available; 315 316 long hr = pReader->Length(&total, &available); 317 assert(hr >= 0); 318 assert(available <= total); 319 assert((pos + 2) <= available); 320 321 short result; 322 323 unsigned char* const p = (unsigned char*)&result; 324 unsigned char* q = p + 2; 325 326 for (;;) 327 { 328 hr = pReader->Read(pos, 1, --q); 329 assert(hr == 0L); 330 331 if (q == p) 332 break; 333 334 ++pos; 335 } 336 337 return result; 338 } 339 340 341 bool mkvparser::Match( 342 IMkvReader* pReader, 343 long long& pos, 344 unsigned long id_, 345 long long& val) 346 347 { 348 assert(pReader); 349 assert(pos >= 0); 350 351 long long total, available; 352 353 long hr = pReader->Length(&total, &available); 354 assert(hr >= 0); 355 assert(available <= total); 356 357 long len; 358 359 const long long id = ReadUInt(pReader, pos, len); 360 assert(id >= 0); 361 assert(len > 0); 362 assert(len <= 8); 363 assert((pos + len) <= available); 364 365 if ((unsigned long)id != id_) 366 return false; 367 368 pos += len; //consume id 369 370 const long long size = ReadUInt(pReader, pos, len); 371 assert(size >= 0); 372 assert(size <= 8); 373 assert(len > 0); 374 assert(len <= 8); 375 assert((pos + len) <= available); 376 377 pos += len; //consume length of size of payload 378 379 val = UnserializeUInt(pReader, pos, size); 380 assert(val >= 0); 381 382 pos += size; //consume size of payload 383 384 return true; 385 } 386 387 bool mkvparser::Match( 388 IMkvReader* pReader, 389 long long& pos, 390 unsigned long id_, 391 char*& val) 392 { 393 assert(pReader); 394 assert(pos >= 0); 395 396 long long total, available; 397 398 long hr = pReader->Length(&total, &available); 399 assert(hr >= 0); 400 assert(available <= total); 401 402 long len; 403 404 const long long id = ReadUInt(pReader, pos, len); 405 assert(id >= 0); 406 assert(len > 0); 407 assert(len <= 8); 408 assert((pos + len) <= available); 409 410 if ((unsigned long)id != id_) 411 return false; 412 413 pos += len; //consume id 414 415 const long long size_ = ReadUInt(pReader, pos, len); 416 assert(size_ >= 0); 417 assert(len > 0); 418 assert(len <= 8); 419 assert((pos + len) <= available); 420 421 pos += len; //consume length of size of payload 422 assert((pos + size_) <= available); 423 424 const size_t size = static_cast<size_t>(size_); 425 val = new char[size+1]; 426 427 for (size_t i = 0; i < size; ++i) 428 { 429 char c; 430 431 hr = pReader->Read(pos + i, 1, (unsigned char*)&c); 432 assert(hr == 0L); 433 434 val[i] = c; 435 436 if (c == '\0') 437 break; 438 439 } 440 441 val[size] = '\0'; 442 pos += size_; //consume size of payload 443 444 return true; 445 } 446 447 #if 0 448 bool mkvparser::Match( 449 IMkvReader* pReader, 450 long long& pos, 451 unsigned long id, 452 wchar_t*& val) 453 { 454 char* str; 455 456 if (!Match(pReader, pos, id, str)) 457 return false; 458 459 const size_t size = mbstowcs(NULL, str, 0); 460 461 if (size == 0) 462 val = NULL; 463 else 464 { 465 val = new wchar_t[size+1]; 466 mbstowcs(val, str, size); 467 val[size] = L'\0'; 468 } 469 470 delete[] str; 471 return true; 472 } 473 #endif 474 475 476 bool mkvparser::Match( 477 IMkvReader* pReader, 478 long long& pos, 479 unsigned long id_, 480 unsigned char*& val, 481 size_t *optionalSize) 482 { 483 assert(pReader); 484 assert(pos >= 0); 485 486 long long total, available; 487 488 long hr = pReader->Length(&total, &available); 489 assert(hr >= 0); 490 assert(available <= total); 491 492 long len; 493 const long long id = ReadUInt(pReader, pos, len); 494 assert(id >= 0); 495 assert(len > 0); 496 assert(len <= 8); 497 assert((pos + len) <= available); 498 499 if ((unsigned long)id != id_) 500 return false; 501 502 pos += len; //consume id 503 504 const long long size_ = ReadUInt(pReader, pos, len); 505 assert(size_ >= 0); 506 assert(len > 0); 507 assert(len <= 8); 508 assert((pos + len) <= available); 509 510 pos += len; //consume length of size of payload 511 assert((pos + size_) <= available); 512 513 const size_t size = static_cast<size_t>(size_); 514 val = new unsigned char[size]; 515 516 if (optionalSize) { 517 *optionalSize = size; 518 } 519 520 for (size_t i = 0; i < size; ++i) 521 { 522 unsigned char b; 523 524 hr = pReader->Read(pos + i, 1, &b); 525 assert(hr == 0L); 526 527 val[i] = b; 528 } 529 530 pos += size_; //consume size of payload 531 return true; 532 } 533 534 535 bool mkvparser::Match( 536 IMkvReader* pReader, 537 long long& pos, 538 unsigned long id_, 539 double& val) 540 { 541 assert(pReader); 542 assert(pos >= 0); 543 544 long long total, available; 545 546 long hr = pReader->Length(&total, &available); 547 assert(hr >= 0); 548 assert(available <= total); 549 long idlen; 550 const long long id = ReadUInt(pReader, pos, idlen); 551 assert(id >= 0); //TODO 552 553 if ((unsigned long)id != id_) 554 return false; 555 556 long sizelen; 557 const long long size = ReadUInt(pReader, pos + idlen, sizelen); 558 559 switch (size) 560 { 561 case 4: 562 case 8: 563 break; 564 default: 565 return false; 566 } 567 568 pos += idlen + sizelen; //consume id and size fields 569 assert((pos + size) <= available); 570 571 if (size == 4) 572 val = Unserialize4Float(pReader, pos); 573 else 574 { 575 assert(size == 8); 576 val = Unserialize8Double(pReader, pos); 577 } 578 579 pos += size; //consume size of payload 580 581 return true; 582 } 583 584 585 bool mkvparser::Match( 586 IMkvReader* pReader, 587 long long& pos, 588 unsigned long id_, 589 short& val) 590 { 591 assert(pReader); 592 assert(pos >= 0); 593 594 long long total, available; 595 596 long hr = pReader->Length(&total, &available); 597 assert(hr >= 0); 598 assert(available <= total); 599 600 long len; 601 const long long id = ReadUInt(pReader, pos, len); 602 assert(id >= 0); 603 assert((pos + len) <= available); 604 605 if ((unsigned long)id != id_) 606 return false; 607 608 pos += len; //consume id 609 610 const long long size = ReadUInt(pReader, pos, len); 611 assert(size <= 2); 612 assert((pos + len) <= available); 613 614 pos += len; //consume length of size of payload 615 assert((pos + size) <= available); 616 617 //TODO: 618 // Generalize this to work for any size signed int 619 if (size == 1) 620 val = Unserialize1SInt(pReader, pos); 621 else 622 val = Unserialize2SInt(pReader, pos); 623 624 pos += size; //consume size of payload 625 626 return true; 627 } 628 629 630 namespace mkvparser 631 { 632 633 EBMLHeader::EBMLHeader(): 634 m_docType(NULL) 635 { 636 } 637 638 EBMLHeader::~EBMLHeader() 639 { 640 delete[] m_docType; 641 } 642 643 long long EBMLHeader::Parse( 644 IMkvReader* pReader, 645 long long& pos) 646 { 647 assert(pReader); 648 649 long long total, available; 650 651 long hr = pReader->Length(&total, &available); 652 653 if (hr < 0) 654 return hr; 655 656 pos = 0; 657 long long end = (1024 < available)? 1024: available; 658 659 for (;;) 660 { 661 unsigned char b = 0; 662 663 while (pos < end) 664 { 665 hr = pReader->Read(pos, 1, &b); 666 667 if (hr < 0) 668 return hr; 669 670 if (b == 0x1A) 671 break; 672 673 ++pos; 674 } 675 676 if (b != 0x1A) 677 { 678 if ((pos >= 1024) || 679 (available >= total) || 680 ((total - available) < 5)) 681 return -1; 682 683 return available + 5; //5 = 4-byte ID + 1st byte of size 684 } 685 686 if ((total - pos) < 5) 687 return E_FILE_FORMAT_INVALID; 688 689 if ((available - pos) < 5) 690 return pos + 5; //try again later 691 692 long len; 693 694 const long long result = ReadUInt(pReader, pos, len); 695 696 if (result < 0) //error 697 return result; 698 699 if (result == 0x0A45DFA3) //ReadId masks-off length indicator bits 700 { 701 assert(len == 4); 702 pos += len; 703 break; 704 } 705 706 ++pos; //throw away just the 0x1A byte, and try again 707 } 708 709 long len; 710 long long result = GetUIntLength(pReader, pos, len); 711 712 if (result < 0) //error 713 return result; 714 715 if (result > 0) //need more data 716 return result; 717 718 assert(len > 0); 719 assert(len <= 8); 720 721 if ((total - pos) < len) 722 return E_FILE_FORMAT_INVALID; 723 if ((available - pos) < len) 724 return pos + len; //try again later 725 726 result = ReadUInt(pReader, pos, len); 727 728 if (result < 0) //error 729 return result; 730 731 pos += len; //consume u-int 732 733 if ((total - pos) < result) 734 return E_FILE_FORMAT_INVALID; 735 736 if ((available - pos) < result) 737 return pos + result; 738 739 end = pos + result; 740 741 m_version = 1; 742 m_readVersion = 1; 743 m_maxIdLength = 4; 744 m_maxSizeLength = 8; 745 m_docTypeVersion = 1; 746 m_docTypeReadVersion = 1; 747 748 while (pos < end) 749 { 750 if (Match(pReader, pos, 0x0286, m_version)) 751 ; 752 else if (Match(pReader, pos, 0x02F7, m_readVersion)) 753 ; 754 else if (Match(pReader, pos, 0x02F2, m_maxIdLength)) 755 ; 756 else if (Match(pReader, pos, 0x02F3, m_maxSizeLength)) 757 ; 758 else if (Match(pReader, pos, 0x0282, m_docType)) 759 ; 760 else if (Match(pReader, pos, 0x0287, m_docTypeVersion)) 761 ; 762 else if (Match(pReader, pos, 0x0285, m_docTypeReadVersion)) 763 ; 764 else 765 { 766 result = ReadUInt(pReader, pos, len); 767 assert(result > 0); 768 assert(len > 0); 769 assert(len <= 8); 770 771 pos += len; 772 assert(pos < end); 773 774 result = ReadUInt(pReader, pos, len); 775 assert(result >= 0); 776 assert(len > 0); 777 assert(len <= 8); 778 779 pos += len + result; 780 assert(pos <= end); 781 } 782 } 783 784 assert(pos == end); 785 786 return 0; 787 } 788 789 790 Segment::Segment( 791 IMkvReader* pReader, 792 long long start, 793 long long size) : 794 m_pReader(pReader), 795 m_start(start), 796 m_size(size), 797 m_pos(start), 798 m_pInfo(NULL), 799 m_pTracks(NULL), 800 m_clusterCount(0) 801 //m_clusterNumber(0) 802 { 803 } 804 805 806 Segment::~Segment() 807 { 808 Cluster** i = m_clusters; 809 Cluster** j = m_clusters + m_clusterCount; 810 811 while (i != j) 812 { 813 Cluster* p = *i++; 814 assert(p); 815 delete p; 816 } 817 818 delete[] m_clusters; 819 820 delete m_pTracks; 821 delete m_pInfo; 822 } 823 824 825 long long Segment::CreateInstance( 826 IMkvReader* pReader, 827 long long pos, 828 Segment*& pSegment) 829 { 830 assert(pReader); 831 assert(pos >= 0); 832 833 pSegment = NULL; 834 835 long long total, available; 836 837 long hr = pReader->Length(&total, &available); 838 assert(hr >= 0); 839 assert(available <= total); 840 841 //I would assume that in practice this loop would execute 842 //exactly once, but we allow for other elements (e.g. Void) 843 //to immediately follow the EBML header. This is fine for 844 //the source filter case (since the entire file is available), 845 //but in the splitter case over a network we should probably 846 //just give up early. We could for example decide only to 847 //execute this loop a maximum of, say, 10 times. 848 849 while (pos < total) 850 { 851 //Read ID 852 853 long len; 854 long long result = GetUIntLength(pReader, pos, len); 855 856 if (result) //error, or too few available bytes 857 return result; 858 859 if ((pos + len) > total) 860 return E_FILE_FORMAT_INVALID; 861 862 if ((pos + len) > available) 863 return pos + len; 864 865 //TODO: if we liberalize the behavior of ReadUInt, we can 866 //probably eliminate having to use GetUIntLength here. 867 const long long id = ReadUInt(pReader, pos, len); 868 869 if (id < 0) //error 870 return id; 871 872 pos += len; //consume ID 873 874 //Read Size 875 876 result = GetUIntLength(pReader, pos, len); 877 878 if (result) //error, or too few available bytes 879 return result; 880 881 if ((pos + len) > total) 882 return E_FILE_FORMAT_INVALID; 883 884 if ((pos + len) > available) 885 return pos + len; 886 887 //TODO: if we liberalize the behavior of ReadUInt, we can 888 //probably eliminate having to use GetUIntLength here. 889 const long long size = ReadUInt(pReader, pos, len); 890 891 if (size < 0) 892 return size; 893 894 pos += len; //consume length of size of element 895 896 //Pos now points to start of payload 897 898 if ((pos + size) > total) 899 return E_FILE_FORMAT_INVALID; 900 901 if (id == 0x08538067) //Segment ID 902 { 903 pSegment = new Segment(pReader, pos, size); 904 assert(pSegment); //TODO 905 906 return 0; //success 907 } 908 909 pos += size; //consume payload 910 } 911 912 assert(pos == total); 913 914 pSegment = new Segment(pReader, pos, 0); 915 assert(pSegment); //TODO 916 917 return 0; //success (sort of) 918 } 919 920 921 long long Segment::ParseHeaders() 922 { 923 //Outermost (level 0) segment object has been constructed, 924 //and pos designates start of payload. We need to find the 925 //inner (level 1) elements. 926 long long total, available; 927 928 long hr = m_pReader->Length(&total, &available); 929 assert(hr >= 0); 930 assert(available <= total); 931 932 const long long stop = m_start + m_size; 933 assert(stop <= total); 934 assert(m_pos <= stop); 935 936 bool bQuit = false; 937 while ((m_pos < stop) && !bQuit) 938 { 939 long long pos = m_pos; 940 941 long len; 942 long long result = GetUIntLength(m_pReader, pos, len); 943 944 if (result) //error, or too few available bytes 945 return result; 946 947 if ((pos + len) > stop) 948 return E_FILE_FORMAT_INVALID; 949 950 if ((pos + len) > available) 951 return pos + len; 952 953 const long long idpos = pos; 954 const long long id = ReadUInt(m_pReader, idpos, len); 955 956 if (id < 0) //error 957 return id; 958 959 pos += len; //consume ID 960 961 //Read Size 962 result = GetUIntLength(m_pReader, pos, len); 963 964 if (result) //error, or too few available bytes 965 return result; 966 967 if ((pos + len) > stop) 968 return E_FILE_FORMAT_INVALID; 969 970 if ((pos + len) > available) 971 return pos + len; 972 973 const long long size = ReadUInt(m_pReader, pos, len); 974 975 if (size < 0) 976 return size; 977 978 pos += len; //consume length of size of element 979 980 //Pos now points to start of payload 981 982 if ((pos + size) > stop) 983 return E_FILE_FORMAT_INVALID; 984 985 //We read EBML elements either in total or nothing at all. 986 987 if ((pos + size) > available) 988 return pos + size; 989 990 if (id == 0x0549A966) //Segment Info ID 991 { 992 assert(m_pInfo == NULL); 993 m_pInfo = new SegmentInfo(this, pos, size); 994 assert(m_pInfo); //TODO 995 996 if (m_pTracks) 997 bQuit = true; 998 } 999 else if (id == 0x0654AE6B) //Tracks ID 1000 { 1001 assert(m_pTracks == NULL); 1002 m_pTracks = new Tracks(this, pos, size); 1003 assert(m_pTracks); //TODO 1004 1005 if (m_pInfo) 1006 bQuit = true; 1007 } 1008 else if (id == 0x0F43B675) //Cluster ID 1009 { 1010 #if 0 1011 if (m_pInfo == NULL) //TODO: liberalize 1012 ; 1013 else if (m_pTracks == NULL) 1014 ; 1015 else 1016 //ParseCluster(idpos, pos, size); 1017 Cluster::Parse(this, m_clusters, pos, size); 1018 #endif 1019 bQuit = true; 1020 } 1021 1022 m_pos = pos + size; //consume payload 1023 } 1024 1025 assert(m_pos <= stop); 1026 1027 return 0; //success 1028 } 1029 1030 1031 long Segment::ParseCluster(Cluster*& pCluster, long long& pos_) const 1032 { 1033 pCluster = NULL; 1034 pos_ = -1; 1035 1036 const long long stop = m_start + m_size; 1037 assert(m_pos <= stop); 1038 1039 long long pos = m_pos; 1040 long long off = -1; 1041 1042 1043 while (pos < stop) 1044 { 1045 long len; 1046 const long long idpos = pos; 1047 1048 const long long id = SyncReadUInt(m_pReader, pos, stop, len); 1049 1050 if (id < 0) //error 1051 return static_cast<long>(id); 1052 1053 if (id == 0) 1054 return E_FILE_FORMAT_INVALID; 1055 1056 pos += len; //consume id 1057 assert(pos < stop); 1058 1059 const long long size = SyncReadUInt(m_pReader, pos, stop, len); 1060 1061 if (size < 0) //error 1062 return static_cast<long>(size); 1063 1064 pos += len; //consume size 1065 assert(pos <= stop); 1066 1067 if (size == 0) //weird 1068 continue; 1069 1070 //pos now points to start of payload 1071 1072 pos += size; //consume payload 1073 assert(pos <= stop); 1074 1075 if (off >= 0) 1076 { 1077 pos_ = idpos; 1078 break; 1079 } 1080 1081 if (id == 0x0F43B675) //Cluster ID 1082 off = idpos - m_start; 1083 } 1084 1085 Segment* const this_ = const_cast<Segment*>(this); 1086 const size_t idx = m_clusterCount; 1087 1088 if (pos >= stop) 1089 { 1090 pos_ = stop; 1091 1092 #if 0 1093 if (off < 0) 1094 { 1095 pCluster = Cluster::CreateEndOfStream(this_, idx); 1096 return 1L; 1097 } 1098 #else 1099 if (off < 0) 1100 return 1L; 1101 #endif 1102 1103 //Reading 0 bytes at pos might work too -- it would depend 1104 //on how the reader is implemented. 1105 1106 unsigned char b; 1107 1108 const long hr = m_pReader->Read(pos - 1, 1, &b); 1109 1110 if (hr < 0) 1111 return hr; 1112 1113 if (hr != 0L) 1114 return E_BUFFER_NOT_FULL; 1115 } 1116 1117 assert(off >= 0); 1118 assert(pos_ >= m_start); 1119 assert(pos_ <= stop); 1120 1121 pCluster = Cluster::Parse(this_, idx, off); 1122 return 0L; 1123 } 1124 1125 1126 bool Segment::AddCluster(Cluster* pCluster, long long pos) 1127 { 1128 assert(pos >= m_start); 1129 1130 const long long stop = m_start + m_size; 1131 assert(pos <= stop); 1132 1133 if (pCluster) 1134 m_clusters[pos] = pCluster; 1135 1136 m_pos = pos; //m_pos >= stop is now we know we have all clusters 1137 1138 return (pos >= stop); 1139 } 1140 1141 1142 long Segment::Load() 1143 { 1144 //Outermost (level 0) segment object has been constructed, 1145 //and pos designates start of payload. We need to find the 1146 //inner (level 1) elements. 1147 const long long stop = m_start + m_size; 1148 #ifdef _DEBUG 1149 { 1150 long long total, available; 1151 1152 long hr = m_pReader->Length(&total, &available); 1153 assert(hr >= 0); 1154 assert(available >= total); 1155 assert(stop <= total); 1156 } 1157 #endif 1158 long long index = m_pos; 1159 1160 m_clusterCount = 0; 1161 1162 while (index < stop) 1163 { 1164 long len = 0; 1165 1166 long long result = GetUIntLength(m_pReader, index, len); 1167 1168 if (result < 0) //error 1169 return static_cast<long>(result); 1170 1171 if ((index + len) > stop) 1172 return E_FILE_FORMAT_INVALID; 1173 1174 const long long idpos = index; 1175 const long long id = ReadUInt(m_pReader, idpos, len); 1176 1177 if (id < 0) //error 1178 return static_cast<long>(id); 1179 1180 index += len; //consume ID 1181 1182 //Read Size 1183 result = GetUIntLength(m_pReader, index, len); 1184 1185 if (result < 0) //error 1186 return static_cast<long>(result); 1187 1188 if ((index + len) > stop) 1189 return E_FILE_FORMAT_INVALID; 1190 1191 const long long size = ReadUInt(m_pReader, index, len); 1192 1193 if (size < 0) //error 1194 return static_cast<long>(size); 1195 1196 index += len; //consume length of size of element 1197 1198 if (id == 0x0F43B675) // Cluster ID 1199 break; 1200 1201 if (id == 0x014D9B74) // SeekHead ID 1202 { 1203 ParseSeekHead(index, size, NULL); 1204 break; 1205 } 1206 index += size; 1207 } 1208 1209 if (m_clusterCount == 0) 1210 return -1L; 1211 1212 while (m_pos < stop) 1213 { 1214 long long pos = m_pos; 1215 1216 long len; 1217 1218 long long result = GetUIntLength(m_pReader, pos, len); 1219 1220 if (result < 0) //error 1221 return static_cast<long>(result); 1222 1223 if ((pos + len) > stop) 1224 return E_FILE_FORMAT_INVALID; 1225 1226 const long long idpos = pos; 1227 const long long id = ReadUInt(m_pReader, idpos, len); 1228 1229 if (id < 0) //error 1230 return static_cast<long>(id); 1231 1232 pos += len; //consume ID 1233 1234 //Read Size 1235 result = GetUIntLength(m_pReader, pos, len); 1236 1237 if (result < 0) //error 1238 return static_cast<long>(result); 1239 1240 if ((pos + len) > stop) 1241 return E_FILE_FORMAT_INVALID; 1242 1243 const long long size = ReadUInt(m_pReader, pos, len); 1244 1245 if (size < 0) //error 1246 return static_cast<long>(size); 1247 1248 pos += len; //consume length of size of element 1249 1250 //Pos now points to start of payload 1251 1252 if ((pos + size) > stop) 1253 return E_FILE_FORMAT_INVALID; 1254 1255 if (id == 0x0F43B675) //Cluster ID 1256 break; 1257 1258 if (id == 0x014D9B74) //SeekHead ID 1259 { 1260 m_clusters = new Cluster*[m_clusterCount]; 1261 size_t index = 0; 1262 1263 ParseSeekHead(pos, size, &index); 1264 assert(index == m_clusterCount); 1265 } 1266 else if (id == 0x0549A966) //Segment Info ID 1267 { 1268 assert(m_pInfo == NULL); 1269 m_pInfo = new SegmentInfo(this, pos, size); 1270 assert(m_pInfo); //TODO 1271 } 1272 else if (id == 0x0654AE6B) //Tracks ID 1273 { 1274 assert(m_pTracks == NULL); 1275 m_pTracks = new Tracks(this, pos, size); 1276 assert(m_pTracks); //TODO 1277 } 1278 1279 m_pos = pos + size; //consume payload 1280 } 1281 1282 assert(m_clusters); 1283 1284 //TODO: see notes above. This check is here (temporarily) to ensure 1285 //that the first seekhead has entries for the clusters (because that's 1286 //when they're loaded). In case we are given a file that lists the 1287 //clusters in a second seekhead, the worst thing that happens is that 1288 //we treat this as an invalid file (which is better then simply 1289 //asserting somewhere). But that's only a work-around. What we need 1290 //to do is be able to handle having multiple seekheads, and having 1291 //clusters listed somewhere besides the first seekhead. 1292 // 1293 //if (m_clusters == NULL) 1294 // return E_FILE_FORMAT_INVALID; 1295 1296 //NOTE: we stop parsing when we reach the first cluster, under the 1297 //assumption all clusters are named in some SeekHead. Clusters 1298 //will have been (pre)loaded, so we indicate that we have all clusters 1299 //by adjusting the parse position: 1300 m_pos = stop; //means "we have all clusters" 1301 1302 return 0L; 1303 } 1304 1305 1306 void Segment::ParseSeekHead(long long start, long long size_, size_t* pIndex) 1307 { 1308 long long pos = start; 1309 const long long stop = start + size_; 1310 while (pos < stop) 1311 { 1312 long len; 1313 1314 const long long id = ReadUInt(m_pReader, pos, len); 1315 assert(id >= 0); //TODO 1316 assert((pos + len) <= stop); 1317 1318 pos += len; //consume ID 1319 1320 const long long size = ReadUInt(m_pReader, pos, len); 1321 assert(size >= 0); 1322 assert((pos + len) <= stop); 1323 1324 pos += len; //consume Size field 1325 assert((pos + size) <= stop); 1326 1327 if (id == 0x0DBB) //SeekEntry ID 1328 ParseSeekEntry(pos, size, pIndex); 1329 1330 pos += size; //consume payload 1331 assert(pos <= stop); 1332 } 1333 1334 assert(pos == stop); 1335 } 1336 1337 1338 void Segment::ParseSecondarySeekHead(long long off, size_t* pIndex) 1339 { 1340 assert(off >= 0); 1341 assert(off < m_size); 1342 1343 long long pos = m_start + off; 1344 const long long stop = m_start + m_size; 1345 1346 long len; 1347 1348 long long result = GetUIntLength(m_pReader, pos, len); 1349 assert(result == 0); 1350 assert((pos + len) <= stop); 1351 1352 const long long idpos = pos; 1353 1354 const long long id = ReadUInt(m_pReader, idpos, len); 1355 assert(id == 0x014D9B74); //SeekHead ID 1356 1357 pos += len; //consume ID 1358 assert(pos < stop); 1359 1360 //Read Size 1361 1362 result = GetUIntLength(m_pReader, pos, len); 1363 assert(result == 0); 1364 assert((pos + len) <= stop); 1365 1366 const long long size = ReadUInt(m_pReader, pos, len); 1367 assert(size >= 0); 1368 1369 pos += len; //consume length of size of element 1370 assert((pos + size) <= stop); 1371 1372 //Pos now points to start of payload 1373 1374 ParseSeekHead(pos, size, pIndex); 1375 } 1376 1377 1378 void Segment::ParseSeekEntry(long long start, long long size_, size_t* pIndex) 1379 { 1380 long long pos = start; 1381 1382 const long long stop = start + size_; 1383 1384 long len; 1385 1386 const long long seekIdId = ReadUInt(m_pReader, pos, len); 1387 //seekIdId; 1388 assert(seekIdId == 0x13AB); //SeekID ID 1389 assert((pos + len) <= stop); 1390 1391 pos += len; //consume id 1392 1393 const long long seekIdSize = ReadUInt(m_pReader, pos, len); 1394 assert(seekIdSize >= 0); 1395 assert((pos + len) <= stop); 1396 1397 pos += len; //consume size 1398 1399 const long long seekId = ReadUInt(m_pReader, pos, len); //payload 1400 assert(seekId >= 0); 1401 assert(len == seekIdSize); 1402 assert((pos + len) <= stop); 1403 1404 pos += seekIdSize; //consume payload 1405 1406 const long long seekPosId = ReadUInt(m_pReader, pos, len); 1407 //seekPosId; 1408 assert(seekPosId == 0x13AC); //SeekPos ID 1409 assert((pos + len) <= stop); 1410 1411 pos += len; //consume id 1412 1413 const long long seekPosSize = ReadUInt(m_pReader, pos, len); 1414 assert(seekPosSize >= 0); 1415 assert((pos + len) <= stop); 1416 1417 pos += len; //consume size 1418 assert((pos + seekPosSize) <= stop); 1419 1420 const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize); 1421 assert(seekOff >= 0); 1422 assert(seekOff < m_size); 1423 1424 pos += seekPosSize; //consume payload 1425 assert(pos == stop); 1426 1427 const long long seekPos = m_start + seekOff; 1428 assert(seekPos < (m_start + m_size)); 1429 1430 if (seekId == 0x0F43B675) //cluster id 1431 { 1432 if (pIndex == NULL) 1433 ++m_clusterCount; 1434 else 1435 { 1436 assert(m_clusters); 1437 assert(m_clusterCount > 0); 1438 1439 size_t& index = *pIndex; 1440 assert(index < m_clusterCount); 1441 1442 Cluster*& pCluster = m_clusters[index]; 1443 1444 pCluster = Cluster::Parse(this, index, seekOff); 1445 assert(pCluster); //TODO 1446 1447 ++index; 1448 } 1449 } 1450 else if (seekId == 0x014D9B74) //SeekHead ID 1451 { 1452 ParseSecondarySeekHead(seekOff, pIndex); 1453 } 1454 } 1455 1456 1457 long long Segment::Unparsed() const 1458 { 1459 const long long stop = m_start + m_size; 1460 1461 const long long result = stop - m_pos; 1462 assert(result >= 0); 1463 1464 return result; 1465 } 1466 1467 1468 #if 0 //NOTE: too inefficient 1469 long long Segment::Load(long long time_ns) 1470 { 1471 if (Unparsed() <= 0) 1472 return 0; 1473 1474 while (m_clusters.empty()) 1475 { 1476 const long long result = Parse(); 1477 1478 if (result) //error, or not enough bytes available 1479 return result; 1480 1481 if (Unparsed() <= 0) 1482 return 0; 1483 } 1484 1485 while (m_clusters.back()->GetTime() < time_ns) 1486 { 1487 const long long result = Parse(); 1488 1489 if (result) //error, or not enough bytes available 1490 return result; 1491 1492 if (Unparsed() <= 0) 1493 return 0; 1494 } 1495 1496 return 0; 1497 } 1498 #endif 1499 1500 1501 Cluster* Segment::GetFirst() 1502 { 1503 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 1504 return &m_eos; 1505 1506 Cluster* const pCluster = m_clusters[0]; 1507 assert(pCluster); 1508 1509 return pCluster; 1510 } 1511 1512 1513 Cluster* Segment::GetLast() 1514 { 1515 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 1516 return &m_eos; 1517 1518 const size_t idx = m_clusterCount - 1; 1519 Cluster* const pCluster = m_clusters[idx]; 1520 assert(pCluster); 1521 1522 return pCluster; 1523 } 1524 1525 1526 unsigned long Segment::GetCount() const 1527 { 1528 //TODO: m_clusterCount should not be long long. 1529 return static_cast<unsigned long>(m_clusterCount); 1530 } 1531 1532 1533 Cluster* Segment::GetNext(const Cluster* pCurr) 1534 { 1535 assert(pCurr); 1536 assert(pCurr != &m_eos); 1537 assert(m_clusters); 1538 assert(m_clusterCount > 0); 1539 1540 size_t idx = pCurr->m_index; 1541 assert(idx < m_clusterCount); 1542 assert(pCurr == m_clusters[idx]); 1543 1544 idx++; 1545 1546 if (idx >= m_clusterCount) 1547 return &m_eos; 1548 1549 Cluster* const pNext = m_clusters[idx]; 1550 assert(pNext); 1551 1552 return pNext; 1553 } 1554 1555 1556 Cluster* Segment::GetCluster(long long time_ns) 1557 { 1558 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 1559 return &m_eos; 1560 1561 { 1562 Cluster* const pCluster = m_clusters[0]; 1563 assert(pCluster); 1564 assert(pCluster->m_index == 0); 1565 1566 if (time_ns <= pCluster->GetTime()) 1567 return pCluster; 1568 } 1569 1570 //Binary search of cluster array 1571 1572 size_t i = 0; 1573 size_t j = m_clusterCount; 1574 1575 while (i < j) 1576 { 1577 //INVARIANT: 1578 //[0, i) <= time_ns 1579 //[i, j) ? 1580 //[j, m_clusterCount) > time_ns 1581 1582 const size_t k = i + (j - i) / 2; 1583 assert(k < m_clusterCount); 1584 1585 Cluster* const pCluster = m_clusters[k]; 1586 assert(pCluster); 1587 assert(pCluster->m_index == k); 1588 1589 const long long t = pCluster->GetTime(); 1590 1591 if (t <= time_ns) 1592 i = k + 1; 1593 else 1594 j = k; 1595 1596 assert(i <= j); 1597 } 1598 1599 assert(i == j); 1600 assert(i > 0); 1601 assert(i <= m_clusterCount); 1602 1603 const size_t k = i - 1; 1604 1605 Cluster* const pCluster = m_clusters[k]; 1606 assert(pCluster); 1607 assert(pCluster->m_index == k); 1608 assert(pCluster->GetTime() <= time_ns); 1609 1610 return pCluster; 1611 } 1612 1613 1614 Tracks* Segment::GetTracks() const 1615 { 1616 return m_pTracks; 1617 } 1618 1619 1620 const SegmentInfo* const Segment::GetInfo() const 1621 { 1622 return m_pInfo; 1623 } 1624 1625 1626 long long Segment::GetDuration() const 1627 { 1628 assert(m_pInfo); 1629 return m_pInfo->GetDuration(); 1630 } 1631 1632 1633 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_) : 1634 m_pSegment(pSegment), 1635 m_start(start), 1636 m_size(size_), 1637 m_pMuxingAppAsUTF8(NULL), 1638 m_pWritingAppAsUTF8(NULL), 1639 m_pTitleAsUTF8(NULL) 1640 { 1641 IMkvReader* const pReader = m_pSegment->m_pReader; 1642 1643 long long pos = start; 1644 const long long stop = start + size_; 1645 1646 m_timecodeScale = 1000000; 1647 m_duration = 0; 1648 1649 1650 while (pos < stop) 1651 { 1652 if (Match(pReader, pos, 0x0AD7B1, m_timecodeScale)) 1653 assert(m_timecodeScale > 0); 1654 1655 else if (Match(pReader, pos, 0x0489, m_duration)) 1656 assert(m_duration >= 0); 1657 1658 else if (Match(pReader, pos, 0x0D80, m_pMuxingAppAsUTF8)) //[4D][80] 1659 assert(m_pMuxingAppAsUTF8); 1660 1661 else if (Match(pReader, pos, 0x1741, m_pWritingAppAsUTF8)) //[57][41] 1662 assert(m_pWritingAppAsUTF8); 1663 1664 else if (Match(pReader, pos, 0x3BA9, m_pTitleAsUTF8)) //[7B][A9] 1665 assert(m_pTitleAsUTF8); 1666 1667 else 1668 { 1669 long len; 1670 1671 const long long id = ReadUInt(pReader, pos, len); 1672 //id; 1673 assert(id >= 0); 1674 assert((pos + len) <= stop); 1675 1676 pos += len; //consume id 1677 assert((stop - pos) > 0); 1678 1679 const long long size = ReadUInt(pReader, pos, len); 1680 assert(size >= 0); 1681 assert((pos + len) <= stop); 1682 1683 pos += len + size; //consume size and payload 1684 assert(pos <= stop); 1685 } 1686 } 1687 1688 assert(pos == stop); 1689 } 1690 1691 SegmentInfo::~SegmentInfo() 1692 { 1693 if (m_pMuxingAppAsUTF8) 1694 { 1695 delete[] m_pMuxingAppAsUTF8; 1696 m_pMuxingAppAsUTF8 = NULL; 1697 } 1698 1699 if (m_pWritingAppAsUTF8) 1700 { 1701 delete[] m_pWritingAppAsUTF8; 1702 m_pWritingAppAsUTF8 = NULL; 1703 } 1704 1705 if (m_pTitleAsUTF8) 1706 { 1707 delete[] m_pTitleAsUTF8; 1708 m_pTitleAsUTF8 = NULL; 1709 } 1710 } 1711 1712 long long SegmentInfo::GetTimeCodeScale() const 1713 { 1714 return m_timecodeScale; 1715 } 1716 1717 1718 long long SegmentInfo::GetDuration() const 1719 { 1720 assert(m_duration >= 0); 1721 assert(m_timecodeScale >= 1); 1722 1723 const double dd = double(m_duration) * double(m_timecodeScale); 1724 const long long d = static_cast<long long>(dd); 1725 1726 return d; 1727 } 1728 1729 const char* SegmentInfo::GetMuxingAppAsUTF8() const 1730 { 1731 return m_pMuxingAppAsUTF8; 1732 } 1733 1734 const char* SegmentInfo::GetWritingAppAsUTF8() const 1735 { 1736 return m_pWritingAppAsUTF8; 1737 } 1738 1739 const char* SegmentInfo::GetTitleAsUTF8() const 1740 { 1741 return m_pTitleAsUTF8; 1742 } 1743 1744 Track::Track(Segment* pSegment, const Info& i) : 1745 m_pSegment(pSegment), 1746 m_info(i) 1747 { 1748 } 1749 1750 Track::~Track() 1751 { 1752 Info& info = const_cast<Info&>(m_info); 1753 info.Clear(); 1754 } 1755 1756 Track::Info::Info(): 1757 type(-1), 1758 number(-1), 1759 uid(-1), 1760 nameAsUTF8(NULL), 1761 codecId(NULL), 1762 codecPrivate(NULL), 1763 codecPrivateSize(0), 1764 codecNameAsUTF8(NULL) 1765 { 1766 } 1767 1768 void Track::Info::Clear() 1769 { 1770 delete[] nameAsUTF8; 1771 nameAsUTF8 = NULL; 1772 1773 delete[] codecId; 1774 codecId = NULL; 1775 1776 delete[] codecPrivate; 1777 codecPrivate = NULL; 1778 1779 delete[] codecNameAsUTF8; 1780 codecNameAsUTF8 = NULL; 1781 } 1782 1783 const BlockEntry* Track::GetEOS() const 1784 { 1785 return &m_eos; 1786 } 1787 1788 long long Track::GetType() const 1789 { 1790 const unsigned long result = static_cast<unsigned long>(m_info.type); 1791 return result; 1792 } 1793 1794 unsigned long Track::GetNumber() const 1795 { 1796 assert(m_info.number >= 0); 1797 const unsigned long result = static_cast<unsigned long>(m_info.number); 1798 return result; 1799 } 1800 1801 const char* Track::GetNameAsUTF8() const 1802 { 1803 return m_info.nameAsUTF8; 1804 } 1805 1806 const char* Track::GetCodecNameAsUTF8() const 1807 { 1808 return m_info.codecNameAsUTF8; 1809 } 1810 1811 1812 const char* Track::GetCodecId() const 1813 { 1814 return m_info.codecId; 1815 } 1816 1817 1818 const unsigned char* Track::GetCodecPrivate(size_t *optionalSize) const 1819 { 1820 if (optionalSize) { 1821 *optionalSize = m_info.codecPrivateSize; 1822 } 1823 return m_info.codecPrivate; 1824 } 1825 1826 1827 long Track::GetFirst(const BlockEntry*& pBlockEntry) const 1828 { 1829 Cluster* const pCluster = m_pSegment->GetFirst(); 1830 1831 //If Segment::GetFirst returns NULL, then this must be a network 1832 //download, and we haven't loaded any clusters yet. In this case, 1833 //returning NULL from Track::GetFirst means the same thing. 1834 1835 if ((pCluster == NULL) || pCluster->EOS()) 1836 { 1837 pBlockEntry = NULL; 1838 return E_BUFFER_NOT_FULL; //return 1L instead? 1839 } 1840 1841 pBlockEntry = pCluster->GetFirst(); 1842 1843 while (pBlockEntry) 1844 { 1845 const Block* const pBlock = pBlockEntry->GetBlock(); 1846 assert(pBlock); 1847 1848 if (pBlock->GetTrackNumber() == (unsigned long)m_info.number) 1849 return 0L; 1850 1851 pBlockEntry = pCluster->GetNext(pBlockEntry); 1852 } 1853 1854 //NOTE: if we get here, it means that we didn't find a block with 1855 //a matching track number. We interpret that as an error (which 1856 //might be too conservative). 1857 1858 pBlockEntry = GetEOS(); //so we can return a non-NULL value 1859 return 1L; 1860 } 1861 1862 1863 long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry) const 1864 { 1865 assert(pCurrEntry); 1866 assert(!pCurrEntry->EOS()); //? 1867 assert(pCurrEntry->GetBlock()->GetTrackNumber() == (unsigned long)m_info.number); 1868 1869 const Cluster* const pCurrCluster = pCurrEntry->GetCluster(); 1870 assert(pCurrCluster); 1871 assert(!pCurrCluster->EOS()); 1872 1873 pNextEntry = pCurrCluster->GetNext(pCurrEntry); 1874 1875 while (pNextEntry) 1876 { 1877 const Block* const pNextBlock = pNextEntry->GetBlock(); 1878 assert(pNextBlock); 1879 1880 if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number) 1881 return 0L; 1882 1883 pNextEntry = pCurrCluster->GetNext(pNextEntry); 1884 } 1885 1886 Segment* pSegment = pCurrCluster->m_pSegment; 1887 Cluster* const pNextCluster = pSegment->GetNext(pCurrCluster); 1888 1889 if ((pNextCluster == NULL) || pNextCluster->EOS()) 1890 { 1891 if (pSegment->Unparsed() <= 0) //all clusters have been loaded 1892 { 1893 pNextEntry = GetEOS(); 1894 return 1L; 1895 } 1896 1897 pNextEntry = NULL; 1898 return E_BUFFER_NOT_FULL; 1899 } 1900 1901 pNextEntry = pNextCluster->GetFirst(); 1902 1903 while (pNextEntry) 1904 { 1905 const Block* const pNextBlock = pNextEntry->GetBlock(); 1906 assert(pNextBlock); 1907 1908 if (pNextBlock->GetTrackNumber() == (unsigned long)m_info.number) 1909 return 0L; 1910 1911 pNextEntry = pNextCluster->GetNext(pNextEntry); 1912 } 1913 1914 //TODO: what has happened here is that we did not find a block 1915 //with a matching track number on the next cluster. It might 1916 //be the case that some cluster beyond the next cluster 1917 //contains a block having a matching track number, but for 1918 //now we terminate the search immediately. We do this so that 1919 //we don't end up searching the entire file looking for the 1920 //next block. Another possibility is to try searching for the next 1921 //block in a small, fixed number of clusters (intead searching 1922 //just the next one), or to terminate the search when when the 1923 //there is a large gap in time, or large gap in file position. It 1924 //might very well be the case that the approach we use here is 1925 //unnecessarily conservative. 1926 1927 //TODO: again, here's a case where we need to return the special 1928 //EOS block. Or something. It's OK if pNext is NULL, because 1929 //we only need it to set the stop time of the media sample. 1930 //(The start time is determined from pCurr, which is non-NULL 1931 //and non-EOS.) The problem is when we set pCurr=pNext; when 1932 //pCurr has the value NULL we interpret that to mean that we 1933 //haven't fully initialized pCurr and we attempt to set it to 1934 //point to the first block for this track. But that's not what 1935 //we want at all; we want the next call to PopulateSample to 1936 //return end-of-stream, not (re)start from the beginning. 1937 // 1938 //One work-around is to send EOS immediately. We would send 1939 //the EOS the next pass anyway, so maybe it's no great loss. The 1940 //only problem is that if this the stream really does end one 1941 //cluster early (relative to other tracks), or the last frame 1942 //happens to be a keyframe ("CanSeekToEnd"). 1943 // 1944 //The problem is that we need a way to mark as stream as 1945 //"at end of stream" without actually being at end of stream. 1946 //We need to give pCurr some value that means "you've reached EOS". 1947 //We can't synthesize the special EOS Cluster immediately 1948 //(when we first open the file, say), because we use the existance 1949 //of that special cluster value to mean that we've read all of 1950 //the clusters (this is a network download, so we can't know apriori 1951 //how many we have). 1952 // 1953 //Or, we could return E_FAIL, and set another bit in the stream 1954 //object itself, to indicate that it should send EOS earlier 1955 //than when (pCurr=pStop). 1956 // 1957 //Or, probably the best solution, when we actually load the 1958 //blocks into a cluster: if we notice that there's no block 1959 //for a track, we synthesize a nonce EOS block for that track. 1960 //That way we always have something to return. But that will 1961 //only work for sequential scan??? 1962 1963 //pNext = NULL; 1964 //return E_FAIL; 1965 pNextEntry = GetEOS(); 1966 return 1L; 1967 } 1968 1969 1970 Track::EOSBlock::EOSBlock() 1971 { 1972 } 1973 1974 1975 bool Track::EOSBlock::EOS() const 1976 { 1977 return true; 1978 } 1979 1980 1981 Cluster* Track::EOSBlock::GetCluster() const 1982 { 1983 return NULL; 1984 } 1985 1986 1987 size_t Track::EOSBlock::GetIndex() const 1988 { 1989 return 0; 1990 } 1991 1992 1993 const Block* Track::EOSBlock::GetBlock() const 1994 { 1995 return NULL; 1996 } 1997 1998 1999 bool Track::EOSBlock::IsBFrame() const 2000 { 2001 return false; 2002 } 2003 2004 2005 VideoTrack::VideoTrack(Segment* pSegment, const Info& i) : 2006 Track(pSegment, i), 2007 m_width(-1), 2008 m_height(-1), 2009 m_rate(-1) 2010 { 2011 assert(i.type == 1); 2012 assert(i.number > 0); 2013 2014 IMkvReader* const pReader = pSegment->m_pReader; 2015 2016 const Settings& s = i.settings; 2017 assert(s.start >= 0); 2018 assert(s.size >= 0); 2019 2020 long long pos = s.start; 2021 assert(pos >= 0); 2022 2023 const long long stop = pos + s.size; 2024 2025 while (pos < stop) 2026 { 2027 #ifdef _DEBUG 2028 long len; 2029 const long long id = ReadUInt(pReader, pos, len); 2030 assert(id >= 0); //TODO: handle error case 2031 assert((pos + len) <= stop); 2032 #endif 2033 if (Match(pReader, pos, 0x30, m_width)) 2034 ; 2035 else if (Match(pReader, pos, 0x3A, m_height)) 2036 ; 2037 else if (Match(pReader, pos, 0x0383E3, m_rate)) 2038 ; 2039 else 2040 { 2041 long len; 2042 const long long id = ReadUInt(pReader, pos, len); 2043 assert(id >= 0); //TODO: handle error case 2044 assert((pos + len) <= stop); 2045 2046 pos += len; //consume id 2047 2048 const long long size = ReadUInt(pReader, pos, len); 2049 assert(size >= 0); //TODO: handle error case 2050 assert((pos + len) <= stop); 2051 2052 pos += len; //consume length of size 2053 assert((pos + size) <= stop); 2054 2055 //pos now designates start of payload 2056 2057 pos += size; //consume payload 2058 assert(pos <= stop); 2059 } 2060 } 2061 2062 return; 2063 } 2064 2065 2066 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const 2067 { 2068 assert(pBlockEntry); 2069 2070 const Block* const pBlock = pBlockEntry->GetBlock(); 2071 assert(pBlock); 2072 assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number); 2073 2074 return pBlock->IsKey(); 2075 } 2076 2077 2078 2079 long long VideoTrack::GetWidth() const 2080 { 2081 return m_width; 2082 } 2083 2084 2085 long long VideoTrack::GetHeight() const 2086 { 2087 return m_height; 2088 } 2089 2090 2091 double VideoTrack::GetFrameRate() const 2092 { 2093 return m_rate; 2094 } 2095 2096 2097 AudioTrack::AudioTrack(Segment* pSegment, const Info& i) : 2098 Track(pSegment, i) 2099 { 2100 assert(i.type == 2); 2101 assert(i.number > 0); 2102 2103 IMkvReader* const pReader = pSegment->m_pReader; 2104 2105 const Settings& s = i.settings; 2106 assert(s.start >= 0); 2107 assert(s.size >= 0); 2108 2109 long long pos = s.start; 2110 assert(pos >= 0); 2111 2112 const long long stop = pos + s.size; 2113 2114 while (pos < stop) 2115 { 2116 #ifdef _DEBUG 2117 long len; 2118 const long long id = ReadUInt(pReader, pos, len); 2119 assert(id >= 0); //TODO: handle error case 2120 assert((pos + len) <= stop); 2121 #endif 2122 if (Match(pReader, pos, 0x35, m_rate)) 2123 ; 2124 else if (Match(pReader, pos, 0x1F, m_channels)) 2125 ; 2126 else if (Match(pReader, pos, 0x2264, m_bitDepth)) 2127 ; 2128 else 2129 { 2130 long len; 2131 const long long id = ReadUInt(pReader, pos, len); 2132 assert(id >= 0); //TODO: handle error case 2133 assert((pos + len) <= stop); 2134 2135 pos += len; //consume id 2136 2137 const long long size = ReadUInt(pReader, pos, len); 2138 assert(size >= 0); //TODO: handle error case 2139 assert((pos + len) <= stop); 2140 2141 pos += len; //consume length of size 2142 assert((pos + size) <= stop); 2143 2144 //pos now designates start of payload 2145 2146 pos += size; //consume payload 2147 assert(pos <= stop); 2148 } 2149 } 2150 2151 return; 2152 } 2153 2154 bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const 2155 { 2156 assert(pBlockEntry); 2157 2158 const Block* const pBlock = pBlockEntry->GetBlock(); 2159 assert(pBlock); 2160 assert(pBlock->GetTrackNumber() == (unsigned long)m_info.number); 2161 2162 return true; 2163 } 2164 2165 2166 double AudioTrack::GetSamplingRate() const 2167 { 2168 return m_rate; 2169 } 2170 2171 2172 long long AudioTrack::GetChannels() const 2173 { 2174 return m_channels; 2175 } 2176 2177 long long AudioTrack::GetBitDepth() const 2178 { 2179 return m_bitDepth; 2180 } 2181 2182 Tracks::Tracks(Segment* pSegment, long long start, long long size_) : 2183 m_pSegment(pSegment), 2184 m_start(start), 2185 m_size(size_), 2186 m_trackEntries(NULL), 2187 m_trackEntriesEnd(NULL) 2188 { 2189 long long stop = m_start + m_size; 2190 IMkvReader* const pReader = m_pSegment->m_pReader; 2191 2192 long long pos1 = m_start; 2193 int count = 0; 2194 2195 while (pos1 < stop) 2196 { 2197 long len; 2198 const long long id = ReadUInt(pReader, pos1, len); 2199 assert(id >= 0); 2200 assert((pos1 + len) <= stop); 2201 2202 pos1 += len; //consume id 2203 2204 const long long size = ReadUInt(pReader, pos1, len); 2205 assert(size >= 0); 2206 assert((pos1 + len) <= stop); 2207 2208 pos1 += len; //consume length of size 2209 2210 //pos now desinates start of element 2211 if (id == 0x2E) //TrackEntry ID 2212 ++count; 2213 2214 pos1 += size; //consume payload 2215 assert(pos1 <= stop); 2216 } 2217 2218 if (count <= 0) 2219 return; 2220 2221 m_trackEntries = new Track*[count]; 2222 m_trackEntriesEnd = m_trackEntries; 2223 2224 long long pos = m_start; 2225 2226 while (pos < stop) 2227 { 2228 long len; 2229 const long long id = ReadUInt(pReader, pos, len); 2230 assert(id >= 0); 2231 assert((pos + len) <= stop); 2232 2233 pos += len; //consume id 2234 2235 const long long size1 = ReadUInt(pReader, pos, len); 2236 assert(size1 >= 0); 2237 assert((pos + len) <= stop); 2238 2239 pos += len; //consume length of size 2240 2241 //pos now desinates start of element 2242 2243 if (id == 0x2E) //TrackEntry ID 2244 ParseTrackEntry(pos, size1, *m_trackEntriesEnd++); 2245 2246 pos += size1; //consume payload 2247 assert(pos <= stop); 2248 } 2249 } 2250 2251 unsigned long Tracks::GetTracksCount() const 2252 { 2253 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; 2254 assert(result >= 0); 2255 2256 return static_cast<unsigned long>(result); 2257 } 2258 2259 2260 void Tracks::ParseTrackEntry( 2261 long long start, 2262 long long size, 2263 Track*& pTrack) 2264 { 2265 IMkvReader* const pReader = m_pSegment->m_pReader; 2266 2267 long long pos = start; 2268 const long long stop = start + size; 2269 2270 Track::Info i; 2271 2272 Track::Settings videoSettings; 2273 videoSettings.start = -1; 2274 2275 Track::Settings audioSettings; 2276 audioSettings.start = -1; 2277 2278 while (pos < stop) 2279 { 2280 #ifdef _DEBUG 2281 long len; 2282 const long long id = ReadUInt(pReader, pos, len); 2283 len; 2284 id; 2285 #endif 2286 if (Match(pReader, pos, 0x57, i.number)) 2287 assert(i.number > 0); 2288 2289 else if (Match(pReader, pos, 0x33C5, i.uid)) 2290 ; 2291 2292 else if (Match(pReader, pos, 0x03, i.type)) 2293 ; 2294 2295 else if (Match(pReader, pos, 0x136E, i.nameAsUTF8)) 2296 assert(i.nameAsUTF8); 2297 2298 else if (Match(pReader, pos, 0x06, i.codecId)) 2299 ; 2300 2301 else if (Match(pReader, pos, 0x23A2, i.codecPrivate, &i.codecPrivateSize)) 2302 ; 2303 2304 else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8)) 2305 assert(i.codecNameAsUTF8); 2306 2307 else 2308 { 2309 long len; 2310 2311 const long long id = ReadUInt(pReader, pos, len); 2312 assert(id >= 0); //TODO: handle error case 2313 assert((pos + len) <= stop); 2314 2315 pos += len; //consume id 2316 2317 const long long size = ReadUInt(pReader, pos, len); 2318 assert(size >= 0); //TODO: handle error case 2319 assert((pos + len) <= stop); 2320 2321 pos += len; //consume length of size 2322 const long long start = pos; 2323 2324 pos += size; //consume payload 2325 assert(pos <= stop); 2326 2327 if (id == 0x60) 2328 { 2329 videoSettings.start = start; 2330 videoSettings.size = size; 2331 } 2332 else if (id == 0x61) 2333 { 2334 audioSettings.start = start; 2335 audioSettings.size = size; 2336 } 2337 } 2338 } 2339 2340 assert(pos == stop); 2341 //TODO: propertly vet info.number, to ensure both its existence, 2342 //and that it is unique among all tracks. 2343 assert(i.number > 0); 2344 2345 //TODO: vet settings, to ensure that video settings (0x60) 2346 //were specified when type = 1, and that audio settings (0x61) 2347 //were specified when type = 2. 2348 if (i.type == 1) //video 2349 { 2350 assert(audioSettings.start < 0); 2351 assert(videoSettings.start >= 0); 2352 2353 i.settings = videoSettings; 2354 2355 VideoTrack* const t = new VideoTrack(m_pSegment, i); 2356 assert(t); //TODO 2357 pTrack = t; 2358 } 2359 else if (i.type == 2) //audio 2360 { 2361 assert(videoSettings.start < 0); 2362 assert(audioSettings.start >= 0); 2363 2364 i.settings = audioSettings; 2365 2366 AudioTrack* const t = new AudioTrack(m_pSegment, i); 2367 assert(t); //TODO 2368 pTrack = t; 2369 } 2370 else 2371 { 2372 // for now we do not support other track types yet. 2373 // TODO: support other track types 2374 i.Clear(); 2375 2376 pTrack = NULL; 2377 } 2378 2379 return; 2380 } 2381 2382 2383 Tracks::~Tracks() 2384 { 2385 Track** i = m_trackEntries; 2386 Track** const j = m_trackEntriesEnd; 2387 2388 while (i != j) 2389 { 2390 Track* pTrack = *i++; 2391 delete pTrack; 2392 pTrack = NULL; 2393 } 2394 2395 delete[] m_trackEntries; 2396 } 2397 2398 2399 Track* Tracks::GetTrackByNumber(unsigned long tn) const 2400 { 2401 Track** i = m_trackEntries; 2402 Track** const j = m_trackEntriesEnd; 2403 2404 while (i != j) 2405 { 2406 Track* const pTrack = *i++; 2407 2408 if (pTrack == NULL) 2409 continue; 2410 2411 if (tn == pTrack->GetNumber()) 2412 return pTrack; 2413 } 2414 2415 return NULL; //not found 2416 } 2417 2418 2419 Track* Tracks::GetTrackByIndex(unsigned long idx) const 2420 { 2421 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; 2422 2423 if (idx >= static_cast<unsigned long>(count)) 2424 return NULL; 2425 2426 return m_trackEntries[idx]; 2427 } 2428 2429 2430 void Cluster::Load() 2431 { 2432 assert(m_pSegment); 2433 2434 if (m_start > 0) 2435 { 2436 assert(m_size > 0); 2437 assert(m_timecode >= 0); 2438 return; 2439 } 2440 2441 assert(m_size == 0); 2442 assert(m_timecode < 0); 2443 2444 IMkvReader* const pReader = m_pSegment->m_pReader; 2445 2446 const long long off = -m_start; //relative to segment 2447 long long pos = m_pSegment->m_start + off; //absolute 2448 2449 long len; 2450 2451 const long long id_ = ReadUInt(pReader, pos, len); 2452 assert(id_ >= 0); 2453 assert(id_ == 0x0F43B675); //Cluster ID 2454 2455 pos += len; //consume id 2456 2457 const long long size_ = ReadUInt(pReader, pos, len); 2458 assert(size_ >= 0); 2459 2460 pos += len; //consume size 2461 2462 m_start = pos; 2463 m_size = size_; 2464 2465 const long long stop = m_start + size_; 2466 2467 long long timecode = -1; 2468 2469 while (pos < stop) 2470 { 2471 if (Match(pReader, pos, 0x67, timecode)) 2472 break; 2473 else 2474 { 2475 const long long id = ReadUInt(pReader, pos, len); 2476 assert(id >= 0); //TODO 2477 assert((pos + len) <= stop); 2478 2479 pos += len; //consume id 2480 2481 const long long size = ReadUInt(pReader, pos, len); 2482 assert(size >= 0); //TODO 2483 assert((pos + len) <= stop); 2484 2485 pos += len; //consume size 2486 2487 if (id == 0x20) //BlockGroup ID 2488 break; 2489 2490 if (id == 0x23) //SimpleBlock ID 2491 break; 2492 2493 pos += size; //consume payload 2494 assert(pos <= stop); 2495 } 2496 } 2497 2498 assert(pos <= stop); 2499 assert(timecode >= 0); 2500 2501 m_timecode = timecode; 2502 } 2503 2504 2505 Cluster* Cluster::Parse( 2506 Segment* pSegment, 2507 size_t idx, 2508 long long off) 2509 { 2510 assert(pSegment); 2511 assert(off >= 0); 2512 assert(off < pSegment->m_size); 2513 Cluster* const pCluster = new Cluster(pSegment, idx, -off); 2514 assert(pCluster); 2515 2516 return pCluster; 2517 } 2518 2519 2520 Cluster::Cluster() : 2521 m_pSegment(NULL), 2522 m_index(0), 2523 m_start(0), 2524 m_size(0), 2525 m_timecode(0), 2526 m_pEntries(NULL), 2527 m_entriesCount(0) 2528 { 2529 } 2530 2531 Cluster::Cluster( 2532 Segment* pSegment, 2533 size_t idx, 2534 long long off) : 2535 m_pSegment(pSegment), 2536 m_index(idx), 2537 m_start(off), 2538 m_size(0), 2539 m_timecode(-1), 2540 m_pEntries(NULL), 2541 m_entriesCount(0) 2542 { 2543 } 2544 2545 2546 Cluster::~Cluster() 2547 { 2548 #if 0 2549 while (!m_pEntries.empty()) 2550 { 2551 BlockEntry* pBlockEntry = m_pEntries.front(); 2552 assert(pBlockEntry); 2553 2554 m_pEntries.pop_front(); 2555 delete pBlockEntry; 2556 } 2557 #else 2558 BlockEntry** i = m_pEntries; 2559 BlockEntry** const j = m_pEntries + m_entriesCount; 2560 while (i != j) 2561 { 2562 BlockEntry* p = *i++; 2563 2564 assert(p); 2565 delete p; 2566 } 2567 2568 delete[] m_pEntries; 2569 #endif 2570 2571 } 2572 2573 bool Cluster::EOS() const 2574 { 2575 return (m_pSegment == 0); 2576 } 2577 2578 2579 void Cluster::LoadBlockEntries() 2580 { 2581 if (m_pEntries) 2582 return; 2583 2584 Load(); 2585 assert(m_timecode >= 0); 2586 assert(m_start > 0); 2587 assert(m_size > 0); 2588 2589 IMkvReader* const pReader = m_pSegment->m_pReader; 2590 2591 long long pos = m_start; 2592 const long long stop = m_start + m_size; 2593 long long timecode = -1; 2594 2595 long long idx = pos; 2596 2597 m_entriesCount = 0; 2598 2599 while (idx < stop) 2600 { 2601 if (Match(pReader, idx, 0x67, timecode)) 2602 assert(timecode == m_timecode); 2603 else 2604 { 2605 long len; 2606 2607 const long long id = ReadUInt(pReader, idx, len); 2608 assert(id >= 0); //TODO 2609 assert((idx + len) <= stop); 2610 2611 idx += len; //consume id 2612 2613 const long long size = ReadUInt(pReader, idx, len); 2614 assert(size >= 0); //TODO 2615 assert((idx + len) <= stop); 2616 2617 idx += len; //consume size 2618 2619 if (id == 0x20) //BlockGroup ID 2620 ++m_entriesCount; 2621 else if (id == 0x23) //SimpleBlock ID 2622 ++m_entriesCount; 2623 2624 idx += size; //consume payload 2625 2626 assert(idx <= stop); 2627 } 2628 } 2629 2630 if (m_entriesCount == 0) 2631 return; 2632 2633 m_pEntries = new BlockEntry*[m_entriesCount]; 2634 size_t index = 0; 2635 2636 while (pos < stop) 2637 { 2638 if (Match(pReader, pos, 0x67, timecode)) 2639 assert(timecode == m_timecode); 2640 else 2641 { 2642 long len; 2643 const long long id = ReadUInt(pReader, pos, len); 2644 assert(id >= 0); //TODO 2645 assert((pos + len) <= stop); 2646 2647 pos += len; //consume id 2648 2649 const long long size = ReadUInt(pReader, pos, len); 2650 assert(size >= 0); //TODO 2651 assert((pos + len) <= stop); 2652 2653 pos += len; //consume size 2654 2655 if (id == 0x20) //BlockGroup ID 2656 ParseBlockGroup(pos, size, index++); 2657 else if (id == 0x23) //SimpleBlock ID 2658 ParseSimpleBlock(pos, size, index++); 2659 2660 pos += size; //consume payload 2661 assert(pos <= stop); 2662 } 2663 } 2664 2665 assert(pos == stop); 2666 assert(timecode >= 0); 2667 assert(index == m_entriesCount); 2668 } 2669 2670 2671 2672 long long Cluster::GetTimeCode() 2673 { 2674 Load(); 2675 return m_timecode; 2676 } 2677 2678 2679 long long Cluster::GetTime() 2680 { 2681 const long long tc = GetTimeCode(); 2682 assert(tc >= 0); 2683 2684 const SegmentInfo* const pInfo = m_pSegment->GetInfo(); 2685 assert(pInfo); 2686 2687 const long long scale = pInfo->GetTimeCodeScale(); 2688 assert(scale >= 1); 2689 2690 const long long t = m_timecode * scale; 2691 2692 return t; 2693 } 2694 2695 2696 void Cluster::ParseBlockGroup(long long start, long long size, size_t index) 2697 { 2698 assert(m_pEntries); 2699 assert(m_entriesCount); 2700 assert(index < m_entriesCount); 2701 2702 BlockGroup* const pGroup = new BlockGroup(this, index, start, size); 2703 assert(pGroup); //TODO 2704 2705 m_pEntries[index] = pGroup; 2706 } 2707 2708 2709 2710 void Cluster::ParseSimpleBlock(long long start, long long size, size_t index) 2711 { 2712 assert(m_pEntries); 2713 assert(m_entriesCount); 2714 assert(index < m_entriesCount); 2715 2716 SimpleBlock* const pSimpleBlock = new SimpleBlock(this, index, start, size); 2717 assert(pSimpleBlock); //TODO 2718 2719 m_pEntries[index] = pSimpleBlock; 2720 } 2721 2722 2723 const BlockEntry* Cluster::GetFirst() 2724 { 2725 LoadBlockEntries(); 2726 2727 return m_pEntries[0]; 2728 } 2729 2730 2731 const BlockEntry* Cluster::GetLast() 2732 { 2733 if (m_entriesCount == 0) 2734 return m_pEntries[0]; 2735 2736 return m_pEntries[m_entriesCount-1]; 2737 } 2738 2739 2740 const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const 2741 { 2742 assert(pEntry); 2743 2744 size_t idx = pEntry->GetIndex(); 2745 2746 ++idx; 2747 2748 if (idx == m_entriesCount) 2749 return NULL; 2750 2751 return m_pEntries[idx]; 2752 2753 } 2754 2755 2756 const BlockEntry* Cluster::GetEntry(const Track* pTrack) 2757 { 2758 2759 assert(pTrack); 2760 2761 if (m_pSegment == NULL) //EOS 2762 return pTrack->GetEOS(); 2763 2764 LoadBlockEntries(); 2765 2766 BlockEntry* i = *m_pEntries; 2767 BlockEntry* j = *m_pEntries + m_entriesCount; 2768 while (i != j) 2769 { 2770 BlockEntry* pEntry = i; 2771 i++; 2772 assert(pEntry); 2773 assert(!pEntry->EOS()); 2774 2775 const Block* const pBlock = pEntry->GetBlock(); 2776 assert(pBlock); 2777 2778 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) 2779 continue; 2780 2781 if (pTrack->VetEntry(pEntry)) 2782 return pEntry; 2783 } 2784 2785 return pTrack->GetEOS(); //no satisfactory block found 2786 } 2787 2788 2789 BlockEntry::BlockEntry() 2790 { 2791 } 2792 2793 2794 BlockEntry::~BlockEntry() 2795 { 2796 } 2797 2798 2799 2800 SimpleBlock::SimpleBlock( 2801 Cluster* pCluster, 2802 size_t idx, 2803 long long start, 2804 long long size) : 2805 m_pCluster(pCluster), 2806 m_index(idx), 2807 m_block(start, size, pCluster->m_pSegment->m_pReader) 2808 { 2809 } 2810 2811 2812 bool SimpleBlock::EOS() const 2813 { 2814 return false; 2815 } 2816 2817 2818 Cluster* SimpleBlock::GetCluster() const 2819 { 2820 return m_pCluster; 2821 } 2822 2823 2824 size_t SimpleBlock::GetIndex() const 2825 { 2826 return m_index; 2827 } 2828 2829 2830 const Block* SimpleBlock::GetBlock() const 2831 { 2832 return &m_block; 2833 } 2834 2835 2836 bool SimpleBlock::IsBFrame() const 2837 { 2838 return false; 2839 } 2840 2841 2842 BlockGroup::BlockGroup( 2843 Cluster* pCluster, 2844 size_t idx, 2845 long long start, 2846 long long size_) : 2847 m_pCluster(pCluster), 2848 m_index(idx), 2849 m_prevTimeCode(0), 2850 m_nextTimeCode(0), 2851 m_pBlock(NULL) //TODO: accept multiple blocks within a block group 2852 { 2853 IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader; 2854 2855 long long pos = start; 2856 const long long stop = start + size_; 2857 2858 bool bSimpleBlock = false; 2859 2860 while (pos < stop) 2861 { 2862 short t; 2863 2864 if (Match(pReader, pos, 0x7B, t)) 2865 { 2866 if (t < 0) 2867 m_prevTimeCode = t; 2868 else if (t > 0) 2869 m_nextTimeCode = t; 2870 else 2871 assert(false); 2872 } 2873 else 2874 { 2875 long len; 2876 const long long id = ReadUInt(pReader, pos, len); 2877 assert(id >= 0); //TODO 2878 assert((pos + len) <= stop); 2879 2880 pos += len; //consume ID 2881 2882 const long long size = ReadUInt(pReader, pos, len); 2883 assert(size >= 0); //TODO 2884 assert((pos + len) <= stop); 2885 2886 pos += len; //consume size 2887 2888 switch (id) 2889 { 2890 case 0x23: //SimpleBlock ID 2891 bSimpleBlock = true; 2892 //YES, FALL THROUGH TO NEXT CASE 2893 2894 case 0x21: //Block ID 2895 ParseBlock(pos, size); 2896 break; 2897 2898 default: 2899 break; 2900 } 2901 2902 pos += size; //consume payload 2903 assert(pos <= stop); 2904 } 2905 } 2906 2907 assert(pos == stop); 2908 assert(m_pBlock); 2909 2910 if (!bSimpleBlock) 2911 m_pBlock->SetKey(m_prevTimeCode >= 0); 2912 } 2913 2914 2915 BlockGroup::~BlockGroup() 2916 { 2917 delete m_pBlock; 2918 } 2919 2920 2921 void BlockGroup::ParseBlock(long long start, long long size) 2922 { 2923 IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader; 2924 2925 Block* const pBlock = new Block(start, size, pReader); 2926 assert(pBlock); //TODO 2927 2928 //TODO: the Matroska spec says you have multiple blocks within the 2929 //same block group, with blocks ranked by priority (the flag bits). 2930 //I haven't ever seen such a file (mkvmux certainly doesn't make 2931 //one), so until then I'll just assume block groups contain a single 2932 //block. 2933 #if 0 2934 m_blocks.push_back(pBlock); 2935 #else 2936 assert(m_pBlock == NULL); 2937 m_pBlock = pBlock; 2938 #endif 2939 2940 #if 0 2941 Track* const pTrack = pBlock->GetTrack(); 2942 assert(pTrack); 2943 2944 pTrack->Insert(pBlock); 2945 #endif 2946 } 2947 2948 2949 bool BlockGroup::EOS() const 2950 { 2951 return false; 2952 } 2953 2954 2955 Cluster* BlockGroup::GetCluster() const 2956 { 2957 return m_pCluster; 2958 } 2959 2960 2961 size_t BlockGroup::GetIndex() const 2962 { 2963 return m_index; 2964 } 2965 2966 2967 const Block* BlockGroup::GetBlock() const 2968 { 2969 return m_pBlock; 2970 } 2971 2972 2973 short BlockGroup::GetPrevTimeCode() const 2974 { 2975 return m_prevTimeCode; 2976 } 2977 2978 2979 short BlockGroup::GetNextTimeCode() const 2980 { 2981 return m_nextTimeCode; 2982 } 2983 2984 2985 bool BlockGroup::IsBFrame() const 2986 { 2987 return (m_nextTimeCode > 0); 2988 } 2989 2990 2991 2992 Block::Block(long long start, long long size_, IMkvReader* pReader) : 2993 m_start(start), 2994 m_size(size_) 2995 { 2996 long long pos = start; 2997 const long long stop = start + size_; 2998 2999 long len; 3000 3001 m_track = ReadUInt(pReader, pos, len); 3002 assert(m_track > 0); 3003 assert((pos + len) <= stop); 3004 3005 pos += len; //consume track number 3006 assert((stop - pos) >= 2); 3007 3008 m_timecode = Unserialize2SInt(pReader, pos); 3009 3010 pos += 2; 3011 assert((stop - pos) >= 1); 3012 3013 const long hr = pReader->Read(pos, 1, &m_flags); 3014 assert(hr == 0L); 3015 3016 ++pos; 3017 assert(pos <= stop); 3018 3019 m_frameOff = pos; 3020 3021 const long long frame_size = stop - pos; 3022 3023 assert(frame_size <= 2147483647L); 3024 3025 m_frameSize = static_cast<long>(frame_size); 3026 } 3027 3028 3029 long long Block::GetTimeCode(Cluster* pCluster) const 3030 { 3031 assert(pCluster); 3032 3033 const long long tc0 = pCluster->GetTimeCode(); 3034 assert(tc0 >= 0); 3035 3036 const long long tc = tc0 + static_cast<long long>(m_timecode); 3037 assert(tc >= 0); 3038 3039 return tc; //unscaled timecode units 3040 } 3041 3042 3043 long long Block::GetTime(Cluster* pCluster) const 3044 { 3045 assert(pCluster); 3046 3047 const long long tc = GetTimeCode(pCluster); 3048 3049 const Segment* const pSegment = pCluster->m_pSegment; 3050 const SegmentInfo* const pInfo = pSegment->GetInfo(); 3051 assert(pInfo); 3052 3053 const long long scale = pInfo->GetTimeCodeScale(); 3054 assert(scale >= 1); 3055 3056 const long long ns = tc * scale; 3057 3058 return ns; 3059 } 3060 3061 3062 unsigned long Block::GetTrackNumber() const 3063 { 3064 assert(m_track > 0); 3065 3066 return static_cast<unsigned long>(m_track); 3067 } 3068 3069 3070 bool Block::IsKey() const 3071 { 3072 return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0); 3073 } 3074 3075 3076 void Block::SetKey(bool bKey) 3077 { 3078 if (bKey) 3079 m_flags |= static_cast<unsigned char>(1 << 7); 3080 else 3081 m_flags &= 0x7F; 3082 } 3083 3084 3085 long Block::GetSize() const 3086 { 3087 return m_frameSize; 3088 } 3089 3090 3091 long Block::Read(IMkvReader* pReader, unsigned char* buf) const 3092 { 3093 3094 assert(pReader); 3095 assert(buf); 3096 3097 const long hr = pReader->Read(m_frameOff, m_frameSize, buf); 3098 3099 return hr; 3100 } 3101 3102 3103 } //end namespace mkvparser 3104