1 // Copyright (c) 2010 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 #ifndef MKVPARSER_HPP 10 #define MKVPARSER_HPP 11 12 #include <cstdlib> 13 #include <cstdio> 14 15 namespace mkvparser 16 { 17 18 const int E_FILE_FORMAT_INVALID = -2; 19 const int E_BUFFER_NOT_FULL = -3; 20 21 class IMkvReader 22 { 23 public: 24 virtual int Read(long long pos, long len, unsigned char* buf) = 0; 25 virtual int Length(long long* total, long long* available) = 0; 26 protected: 27 virtual ~IMkvReader(); 28 }; 29 30 long long GetUIntLength(IMkvReader*, long long, long&); 31 long long ReadUInt(IMkvReader*, long long, long&); 32 long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&); 33 long long UnserializeUInt(IMkvReader*, long long pos, long long size); 34 float Unserialize4Float(IMkvReader*, long long); 35 double Unserialize8Double(IMkvReader*, long long); 36 short Unserialize2SInt(IMkvReader*, long long); 37 signed char Unserialize1SInt(IMkvReader*, long long); 38 bool Match(IMkvReader*, long long&, unsigned long, long long&); 39 bool Match(IMkvReader*, long long&, unsigned long, char*&); 40 bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&); 41 bool Match(IMkvReader*, long long&, unsigned long, double&); 42 bool Match(IMkvReader*, long long&, unsigned long, short&); 43 44 void GetVersion(int& major, int& minor, int& build, int& revision); 45 46 struct EBMLHeader 47 { 48 EBMLHeader(); 49 ~EBMLHeader(); 50 long long m_version; 51 long long m_readVersion; 52 long long m_maxIdLength; 53 long long m_maxSizeLength; 54 char* m_docType; 55 long long m_docTypeVersion; 56 long long m_docTypeReadVersion; 57 58 long long Parse(IMkvReader*, long long&); 59 void Init(); 60 }; 61 62 63 class Segment; 64 class Track; 65 class Cluster; 66 67 class Block 68 { 69 Block(const Block&); 70 Block& operator=(const Block&); 71 72 public: 73 const long long m_start; 74 const long long m_size; 75 76 Block(long long start, long long size, IMkvReader*); 77 ~Block(); 78 79 long long GetTrackNumber() const; 80 long long GetTimeCode(const Cluster*) const; //absolute, but not scaled 81 long long GetTime(const Cluster*) const; //absolute, and scaled (ns) 82 bool IsKey() const; 83 void SetKey(bool); 84 bool IsInvisible() const; 85 86 int GetFrameCount() const; //to index frames: [0, count) 87 88 struct Frame 89 { 90 long long pos; //absolute offset 91 long len; 92 93 long Read(IMkvReader*, unsigned char*) const; 94 }; 95 96 const Frame& GetFrame(int frame_index) const; 97 98 private: 99 long long m_track; //Track::Number() 100 short m_timecode; //relative to cluster 101 unsigned char m_flags; 102 103 Frame* m_frames; 104 int m_frame_count; 105 106 }; 107 108 109 class BlockEntry 110 { 111 BlockEntry(const BlockEntry&); 112 BlockEntry& operator=(const BlockEntry&); 113 114 public: 115 virtual ~BlockEntry(); 116 virtual bool EOS() const = 0; 117 virtual const Cluster* GetCluster() const = 0; 118 virtual size_t GetIndex() const = 0; 119 virtual const Block* GetBlock() const = 0; 120 //virtual bool IsBFrame() const = 0; 121 122 protected: 123 BlockEntry(); 124 125 }; 126 127 128 class SimpleBlock : public BlockEntry 129 { 130 SimpleBlock(const SimpleBlock&); 131 SimpleBlock& operator=(const SimpleBlock&); 132 133 public: 134 SimpleBlock(Cluster*, size_t, long long start, long long size); 135 136 bool EOS() const; 137 const Cluster* GetCluster() const; 138 size_t GetIndex() const; 139 const Block* GetBlock() const; 140 //bool IsBFrame() const; 141 142 protected: 143 Cluster* const m_pCluster; 144 const size_t m_index; 145 Block m_block; 146 147 }; 148 149 150 class BlockGroup : public BlockEntry 151 { 152 BlockGroup(const BlockGroup&); 153 BlockGroup& operator=(const BlockGroup&); 154 155 public: 156 BlockGroup(Cluster*, size_t, long long, long long); 157 ~BlockGroup(); 158 159 bool EOS() const; 160 const Cluster* GetCluster() const; 161 size_t GetIndex() const; 162 const Block* GetBlock() const; 163 //bool IsBFrame() const; 164 165 short GetPrevTimeCode() const; //relative to block's time 166 short GetNextTimeCode() const; //as above 167 168 protected: 169 Cluster* const m_pCluster; 170 const size_t m_index; 171 172 private: 173 BlockGroup(Cluster*, size_t, unsigned long); 174 void ParseBlock(long long start, long long size); 175 176 short m_prevTimeCode; 177 short m_nextTimeCode; 178 179 //TODO: the Matroska spec says you can have multiple blocks within the 180 //same block group, with blocks ranked by priority (the flag bits). 181 //For now we just cache a single block. 182 #if 0 183 typedef std::deque<Block*> blocks_t; 184 blocks_t m_blocks; //In practice should contain only a single element. 185 #else 186 Block* m_pBlock; 187 #endif 188 189 }; 190 191 192 class Track 193 { 194 Track(const Track&); 195 Track& operator=(const Track&); 196 197 public: 198 Segment* const m_pSegment; 199 const long long m_element_start; 200 const long long m_element_size; 201 virtual ~Track(); 202 203 long long GetType() const; 204 long long GetNumber() const; 205 unsigned long long GetUid() const; 206 const char* GetNameAsUTF8() const; 207 const char* GetCodecNameAsUTF8() const; 208 const char* GetCodecId() const; 209 const unsigned char* GetCodecPrivate(size_t&) const; 210 bool GetLacing() const; 211 212 const BlockEntry* GetEOS() const; 213 214 struct Settings 215 { 216 long long start; 217 long long size; 218 }; 219 220 struct Info 221 { 222 long long type; 223 long long number; 224 unsigned long long uid; 225 char* nameAsUTF8; 226 char* codecId; 227 unsigned char* codecPrivate; 228 size_t codecPrivateSize; 229 char* codecNameAsUTF8; 230 bool lacing; 231 Settings settings; 232 233 Info(); 234 void Clear(); 235 }; 236 237 long GetFirst(const BlockEntry*&) const; 238 long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; 239 virtual bool VetEntry(const BlockEntry*) const = 0; 240 virtual long Seek(long long time_ns, const BlockEntry*&) const = 0; 241 242 protected: 243 Track( 244 Segment*, 245 const Info&, 246 long long element_start, 247 long long element_size); 248 const Info m_info; 249 250 class EOSBlock : public BlockEntry 251 { 252 public: 253 EOSBlock(); 254 255 bool EOS() const; 256 const Cluster* GetCluster() const; 257 size_t GetIndex() const; 258 const Block* GetBlock() const; 259 bool IsBFrame() const; 260 }; 261 262 EOSBlock m_eos; 263 264 }; 265 266 267 class VideoTrack : public Track 268 { 269 VideoTrack(const VideoTrack&); 270 VideoTrack& operator=(const VideoTrack&); 271 272 public: 273 VideoTrack( 274 Segment*, 275 const Info&, 276 long long element_start, 277 long long element_size); 278 long long GetWidth() const; 279 long long GetHeight() const; 280 double GetFrameRate() const; 281 282 bool VetEntry(const BlockEntry*) const; 283 long Seek(long long time_ns, const BlockEntry*&) const; 284 285 private: 286 long long m_width; 287 long long m_height; 288 double m_rate; 289 290 }; 291 292 293 class AudioTrack : public Track 294 { 295 AudioTrack(const AudioTrack&); 296 AudioTrack& operator=(const AudioTrack&); 297 298 public: 299 AudioTrack( 300 Segment*, 301 const Info&, 302 long long element_start, 303 long long element_size); 304 double GetSamplingRate() const; 305 long long GetChannels() const; 306 long long GetBitDepth() const; 307 bool VetEntry(const BlockEntry*) const; 308 long Seek(long long time_ns, const BlockEntry*&) const; 309 310 private: 311 double m_rate; 312 long long m_channels; 313 long long m_bitDepth; 314 }; 315 316 317 class Tracks 318 { 319 Tracks(const Tracks&); 320 Tracks& operator=(const Tracks&); 321 322 public: 323 Segment* const m_pSegment; 324 const long long m_start; 325 const long long m_size; 326 const long long m_element_start; 327 const long long m_element_size; 328 329 Tracks( 330 Segment*, 331 long long start, 332 long long size, 333 long long element_start, 334 long long element_size); 335 virtual ~Tracks(); 336 337 const Track* GetTrackByNumber(unsigned long tn) const; 338 const Track* GetTrackByIndex(unsigned long idx) const; 339 340 private: 341 Track** m_trackEntries; 342 Track** m_trackEntriesEnd; 343 344 void ParseTrackEntry( 345 long long, 346 long long, 347 Track*&, 348 long long element_start, 349 long long element_size); 350 351 public: 352 unsigned long GetTracksCount() const; 353 }; 354 355 356 class SegmentInfo 357 { 358 SegmentInfo(const SegmentInfo&); 359 SegmentInfo& operator=(const SegmentInfo&); 360 361 public: 362 Segment* const m_pSegment; 363 const long long m_start; 364 const long long m_size; 365 const long long m_element_start; 366 const long long m_element_size; 367 368 SegmentInfo( 369 Segment*, 370 long long start, 371 long long size, 372 long long element_start, 373 long long element_size); 374 375 ~SegmentInfo(); 376 377 long long GetTimeCodeScale() const; 378 long long GetDuration() const; //scaled 379 const char* GetMuxingAppAsUTF8() const; 380 const char* GetWritingAppAsUTF8() const; 381 const char* GetTitleAsUTF8() const; 382 383 private: 384 long long m_timecodeScale; 385 double m_duration; 386 char* m_pMuxingAppAsUTF8; 387 char* m_pWritingAppAsUTF8; 388 char* m_pTitleAsUTF8; 389 }; 390 391 392 class SeekHead 393 { 394 SeekHead(const SeekHead&); 395 SeekHead& operator=(const SeekHead&); 396 397 public: 398 Segment* const m_pSegment; 399 const long long m_start; 400 const long long m_size; 401 const long long m_element_start; 402 const long long m_element_size; 403 404 SeekHead( 405 Segment*, 406 long long start, 407 long long size, 408 long long element_start, 409 long long element_size); 410 411 ~SeekHead(); 412 413 struct Entry 414 { 415 long long id; 416 long long pos; 417 }; 418 419 int GetCount() const; 420 const Entry* GetEntry(int idx) const; 421 422 private: 423 Entry* m_entries; 424 int m_count; 425 426 static void ParseEntry( 427 IMkvReader*, 428 long long pos, 429 long long size, 430 Entry*&); 431 432 }; 433 434 class Cues; 435 class CuePoint 436 { 437 friend class Cues; 438 439 CuePoint(long, long long); 440 ~CuePoint(); 441 442 CuePoint(const CuePoint&); 443 CuePoint& operator=(const CuePoint&); 444 445 public: 446 long long m_element_start; 447 long long m_element_size; 448 449 void Load(IMkvReader*); 450 451 long long GetTimeCode() const; //absolute but unscaled 452 long long GetTime(const Segment*) const; //absolute and scaled (ns units) 453 454 struct TrackPosition 455 { 456 long long m_track; 457 long long m_pos; //of cluster 458 long long m_block; 459 //codec_state //defaults to 0 460 //reference = clusters containing req'd referenced blocks 461 // reftime = timecode of the referenced block 462 463 void Parse(IMkvReader*, long long, long long); 464 }; 465 466 const TrackPosition* Find(const Track*) const; 467 468 private: 469 const long m_index; 470 long long m_timecode; 471 TrackPosition* m_track_positions; 472 size_t m_track_positions_count; 473 474 }; 475 476 477 class Cues 478 { 479 friend class Segment; 480 481 Cues( 482 Segment*, 483 long long start, 484 long long size, 485 long long element_start, 486 long long element_size); 487 ~Cues(); 488 489 Cues(const Cues&); 490 Cues& operator=(const Cues&); 491 492 public: 493 Segment* const m_pSegment; 494 const long long m_start; 495 const long long m_size; 496 const long long m_element_start; 497 const long long m_element_size; 498 499 bool Find( //lower bound of time_ns 500 long long time_ns, 501 const Track*, 502 const CuePoint*&, 503 const CuePoint::TrackPosition*&) const; 504 505 #if 0 506 bool FindNext( //upper_bound of time_ns 507 long long time_ns, 508 const Track*, 509 const CuePoint*&, 510 const CuePoint::TrackPosition*&) const; 511 #endif 512 513 const CuePoint* GetFirst() const; 514 const CuePoint* GetLast() const; 515 const CuePoint* GetNext(const CuePoint*) const; 516 517 const BlockEntry* GetBlock( 518 const CuePoint*, 519 const CuePoint::TrackPosition*) const; 520 521 bool LoadCuePoint() const; 522 long GetCount() const; //loaded only 523 //long GetTotal() const; //loaded + preloaded 524 bool DoneParsing() const; 525 526 private: 527 void Init() const; 528 void PreloadCuePoint(long&, long long) const; 529 530 mutable CuePoint** m_cue_points; 531 mutable long m_count; 532 mutable long m_preload_count; 533 mutable long long m_pos; 534 535 }; 536 537 538 class Cluster 539 { 540 friend class Segment; 541 542 Cluster(const Cluster&); 543 Cluster& operator=(const Cluster&); 544 545 public: 546 Segment* const m_pSegment; 547 548 public: 549 static Cluster* Create( 550 Segment*, 551 long index, //index in segment 552 long long off); //offset relative to segment 553 //long long element_size); 554 555 Cluster(); //EndOfStream 556 ~Cluster(); 557 558 bool EOS() const; 559 560 long long GetTimeCode() const; //absolute, but not scaled 561 long long GetTime() const; //absolute, and scaled (nanosecond units) 562 long long GetFirstTime() const; //time (ns) of first (earliest) block 563 long long GetLastTime() const; //time (ns) of last (latest) block 564 565 const BlockEntry* GetFirst() const; 566 const BlockEntry* GetLast() const; 567 const BlockEntry* GetNext(const BlockEntry*) const; 568 const BlockEntry* GetEntry(const Track*, long long ns = -1) const; 569 const BlockEntry* GetEntry( 570 const CuePoint&, 571 const CuePoint::TrackPosition&) const; 572 const BlockEntry* GetMaxKey(const VideoTrack*) const; 573 574 // static bool HasBlockEntries(const Segment*, long long); 575 576 static long HasBlockEntries( 577 const Segment*, 578 long long idoff, 579 long long& pos, 580 long& size); 581 582 long GetEntryCount() const; 583 584 void Load() const; 585 long Load(long long& pos, long& size) const; 586 587 void LoadBlockEntries() const; 588 589 long Parse(long long& pos, long& size) const; 590 long GetEntry(long index, const mkvparser::BlockEntry*&) const; 591 592 protected: 593 Cluster( 594 Segment*, 595 long index, 596 long long element_start); 597 //long long element_size); 598 599 public: 600 const long long m_element_start; 601 long long GetPosition() const; //offset relative to segment 602 603 long GetIndex() const; 604 long long GetElementSize() const; 605 //long long GetPayloadSize() const; 606 607 //long long Unparsed() const; 608 609 private: 610 long m_index; 611 mutable long long m_pos; 612 //mutable long long m_size; 613 mutable long long m_element_size; 614 mutable long long m_timecode; 615 mutable BlockEntry** m_entries; 616 mutable long m_entries_size; 617 mutable long m_entries_count; 618 619 long ParseSimpleBlock(long long, long long&, long&) const; 620 long ParseBlockGroup(long long, long long&, long&) const; 621 622 void CreateBlock(long long id, long long pos, long long size) const; 623 void CreateBlockGroup(long long, long long, BlockEntry**&) const; 624 void CreateSimpleBlock(long long, long long, BlockEntry**&) const; 625 626 }; 627 628 629 class Segment 630 { 631 friend class Cues; 632 friend class VideoTrack; 633 friend class AudioTrack; 634 635 Segment(const Segment&); 636 Segment& operator=(const Segment&); 637 638 private: 639 Segment(IMkvReader*, long long pos, long long size); 640 641 public: 642 IMkvReader* const m_pReader; 643 const long long m_start; //posn of segment payload 644 const long long m_size; //size of segment payload 645 Cluster m_eos; //TODO: make private? 646 647 static long long CreateInstance(IMkvReader*, long long, Segment*&); 648 ~Segment(); 649 650 long Load(); //loads headers and all clusters 651 652 //for incremental loading 653 long long Unparsed() const; 654 long long ParseHeaders(); //stops when first cluster is found 655 //long FindNextCluster(long long& pos, long& size) const; 656 long LoadCluster(long long& pos, long& size); //load one cluster 657 long LoadCluster(); 658 659 long ParseNext( 660 const Cluster* pCurr, 661 const Cluster*& pNext, 662 long long& pos, 663 long& size); 664 665 #if 0 666 //This pair parses one cluster, but only changes the state of the 667 //segment object when the cluster is actually added to the index. 668 long ParseCluster(long long& cluster_pos, long long& new_pos) const; 669 bool AddCluster(long long cluster_pos, long long new_pos); 670 #endif 671 672 const SeekHead* GetSeekHead() const; 673 const Tracks* GetTracks() const; 674 const SegmentInfo* GetInfo() const; 675 const Cues* GetCues() const; 676 677 long long GetDuration() const; 678 679 unsigned long GetCount() const; 680 const Cluster* GetFirst() const; 681 const Cluster* GetLast() const; 682 const Cluster* GetNext(const Cluster*); 683 684 const Cluster* FindCluster(long long time_nanoseconds) const; 685 //const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; 686 687 const Cluster* FindOrPreloadCluster(long long pos); 688 689 long ParseCues( 690 long long cues_off, //offset relative to start of segment 691 long long& parse_pos, 692 long& parse_len); 693 694 private: 695 696 long long m_pos; //absolute file posn; what has been consumed so far 697 Cluster* m_pUnknownSize; 698 699 SeekHead* m_pSeekHead; 700 SegmentInfo* m_pInfo; 701 Tracks* m_pTracks; 702 Cues* m_pCues; 703 Cluster** m_clusters; 704 long m_clusterCount; //number of entries for which m_index >= 0 705 long m_clusterPreloadCount; //number of entries for which m_index < 0 706 long m_clusterSize; //array size 707 708 long DoLoadCluster(long long&, long&); 709 long DoLoadClusterUnknownSize(long long&, long&); 710 long DoParseNext(const Cluster*&, long long&, long&); 711 712 void AppendCluster(Cluster*); 713 void PreloadCluster(Cluster*, ptrdiff_t); 714 715 //void ParseSeekHead(long long pos, long long size); 716 //void ParseSeekEntry(long long pos, long long size); 717 //void ParseCues(long long); 718 719 const BlockEntry* GetBlock( 720 const CuePoint&, 721 const CuePoint::TrackPosition&); 722 723 }; 724 725 } //end namespace mkvparser 726 727 inline long mkvparser::Segment::LoadCluster() 728 { 729 long long pos; 730 long size; 731 732 return LoadCluster(pos, size); 733 } 734 735 #endif //MKVPARSER_HPP 736