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