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 }; 60 61 62 class Segment; 63 class Track; 64 class Cluster; 65 66 class Block 67 { 68 Block(const Block&); 69 Block& operator=(const Block&); 70 71 public: 72 const long long m_start; 73 const long long m_size; 74 75 Block(long long start, long long size, IMkvReader*); 76 77 long long GetTrackNumber() const; 78 long long GetTimeCode(Cluster*) const; //absolute, but not scaled 79 long long GetTime(Cluster*) const; //absolute, and scaled (ns units) 80 bool IsKey() const; 81 void SetKey(bool); 82 83 unsigned char Flags() const; 84 85 long long GetOffset() const; 86 long GetSize() const; 87 long Read(IMkvReader*, unsigned char*) const; 88 89 private: 90 long long m_track; //Track::Number() 91 short m_timecode; //relative to cluster 92 unsigned char m_flags; 93 long long m_frameOff; 94 long m_frameSize; 95 96 }; 97 98 99 class BlockEntry 100 { 101 BlockEntry(const BlockEntry&); 102 BlockEntry& operator=(const BlockEntry&); 103 104 public: 105 virtual ~BlockEntry(); 106 virtual bool EOS() const = 0; 107 virtual Cluster* GetCluster() const = 0; 108 virtual size_t GetIndex() const = 0; 109 virtual const Block* GetBlock() const = 0; 110 virtual bool IsBFrame() const = 0; 111 112 protected: 113 BlockEntry(); 114 115 }; 116 117 118 class SimpleBlock : public BlockEntry 119 { 120 SimpleBlock(const SimpleBlock&); 121 SimpleBlock& operator=(const SimpleBlock&); 122 123 public: 124 SimpleBlock(Cluster*, size_t, long long start, long long size); 125 126 bool EOS() const; 127 Cluster* GetCluster() const; 128 size_t GetIndex() const; 129 const Block* GetBlock() const; 130 bool IsBFrame() const; 131 132 protected: 133 Cluster* const m_pCluster; 134 const size_t m_index; 135 Block m_block; 136 137 }; 138 139 140 class BlockGroup : public BlockEntry 141 { 142 BlockGroup(const BlockGroup&); 143 BlockGroup& operator=(const BlockGroup&); 144 145 public: 146 BlockGroup(Cluster*, size_t, long long, long long); 147 ~BlockGroup(); 148 149 bool EOS() const; 150 Cluster* GetCluster() const; 151 size_t GetIndex() const; 152 const Block* GetBlock() const; 153 bool IsBFrame() const; 154 155 short GetPrevTimeCode() const; //relative to block's time 156 short GetNextTimeCode() const; //as above 157 158 protected: 159 Cluster* const m_pCluster; 160 const size_t m_index; 161 162 private: 163 BlockGroup(Cluster*, size_t, unsigned long); 164 void ParseBlock(long long start, long long size); 165 166 short m_prevTimeCode; 167 short m_nextTimeCode; 168 169 //TODO: the Matroska spec says you can have multiple blocks within the 170 //same block group, with blocks ranked by priority (the flag bits). 171 //For now we just cache a single block. 172 #if 0 173 typedef std::deque<Block*> blocks_t; 174 blocks_t m_blocks; //In practice should contain only a single element. 175 #else 176 Block* m_pBlock; 177 #endif 178 179 }; 180 181 182 class Track 183 { 184 Track(const Track&); 185 Track& operator=(const Track&); 186 187 public: 188 Segment* const m_pSegment; 189 virtual ~Track(); 190 191 long long GetType() const; 192 long long GetNumber() const; 193 const char* GetNameAsUTF8() const; 194 const char* GetCodecNameAsUTF8() const; 195 const char* GetCodecId() const; 196 const unsigned char* GetCodecPrivate(size_t&) const; 197 198 const BlockEntry* GetEOS() const; 199 200 struct Settings 201 { 202 long long start; 203 long long size; 204 }; 205 206 struct Info 207 { 208 long long type; 209 long long number; 210 long long uid; 211 char* nameAsUTF8; 212 char* codecId; 213 unsigned char* codecPrivate; 214 size_t codecPrivateSize; 215 char* codecNameAsUTF8; 216 Settings settings; 217 Info(); 218 void Clear(); 219 }; 220 221 long GetFirst(const BlockEntry*&) const; 222 long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; 223 virtual bool VetEntry(const BlockEntry*) const = 0; 224 225 protected: 226 Track(Segment*, const Info&); 227 const Info m_info; 228 229 class EOSBlock : public BlockEntry 230 { 231 public: 232 EOSBlock(); 233 234 bool EOS() const; 235 Cluster* GetCluster() const; 236 size_t GetIndex() const; 237 const Block* GetBlock() const; 238 bool IsBFrame() const; 239 }; 240 241 EOSBlock m_eos; 242 243 }; 244 245 246 class VideoTrack : public Track 247 { 248 VideoTrack(const VideoTrack&); 249 VideoTrack& operator=(const VideoTrack&); 250 251 public: 252 VideoTrack(Segment*, const Info&); 253 long long GetWidth() const; 254 long long GetHeight() const; 255 double GetFrameRate() const; 256 257 bool VetEntry(const BlockEntry*) const; 258 259 private: 260 long long m_width; 261 long long m_height; 262 double m_rate; 263 264 }; 265 266 267 class AudioTrack : public Track 268 { 269 AudioTrack(const AudioTrack&); 270 AudioTrack& operator=(const AudioTrack&); 271 272 public: 273 AudioTrack(Segment*, const Info&); 274 double GetSamplingRate() const; 275 long long GetChannels() const; 276 long long GetBitDepth() const; 277 bool VetEntry(const BlockEntry*) const; 278 279 private: 280 double m_rate; 281 long long m_channels; 282 long long m_bitDepth; 283 }; 284 285 286 class Tracks 287 { 288 Tracks(const Tracks&); 289 Tracks& operator=(const Tracks&); 290 291 public: 292 Segment* const m_pSegment; 293 const long long m_start; 294 const long long m_size; 295 296 Tracks(Segment*, long long start, long long size); 297 virtual ~Tracks(); 298 299 Track* GetTrackByNumber(unsigned long tn) const; 300 Track* GetTrackByIndex(unsigned long idx) const; 301 302 private: 303 Track** m_trackEntries; 304 Track** m_trackEntriesEnd; 305 306 void ParseTrackEntry(long long, long long, Track*&); 307 308 public: 309 unsigned long GetTracksCount() const; 310 }; 311 312 313 class SegmentInfo 314 { 315 SegmentInfo(const SegmentInfo&); 316 SegmentInfo& operator=(const SegmentInfo&); 317 318 public: 319 Segment* const m_pSegment; 320 const long long m_start; 321 const long long m_size; 322 323 SegmentInfo(Segment*, long long start, long long size); 324 ~SegmentInfo(); 325 long long GetTimeCodeScale() const; 326 long long GetDuration() const; //scaled 327 const char* GetMuxingAppAsUTF8() const; 328 const char* GetWritingAppAsUTF8() const; 329 const char* GetTitleAsUTF8() const; 330 331 private: 332 long long m_timecodeScale; 333 double m_duration; 334 char* m_pMuxingAppAsUTF8; 335 char* m_pWritingAppAsUTF8; 336 char* m_pTitleAsUTF8; 337 }; 338 339 class Cues; 340 class CuePoint 341 { 342 friend class Cues; 343 344 CuePoint(size_t, long long); 345 ~CuePoint(); 346 347 CuePoint(const CuePoint&); 348 CuePoint& operator=(const CuePoint&); 349 350 public: 351 void Load(IMkvReader*); 352 353 long long GetTimeCode() const; //absolute but unscaled 354 long long GetTime(Segment*) const; //absolute and scaled (ns units) 355 356 struct TrackPosition 357 { 358 long long m_track; 359 long long m_pos; //of cluster 360 long long m_block; 361 //codec_state //defaults to 0 362 //reference = clusters containing req'd referenced blocks 363 // reftime = timecode of the referenced block 364 365 void Parse(IMkvReader*, long long, long long); 366 }; 367 368 const TrackPosition* Find(const Track*) const; 369 370 private: 371 const size_t m_index; 372 long long m_timecode; 373 TrackPosition* m_track_positions; 374 size_t m_track_positions_count; 375 376 }; 377 378 379 class Cues 380 { 381 friend class Segment; 382 383 Cues(Segment*, long long start, long long size); 384 ~Cues(); 385 386 Cues(const Cues&); 387 Cues& operator=(const Cues&); 388 389 public: 390 Segment* const m_pSegment; 391 const long long m_start; 392 const long long m_size; 393 394 bool Find( //lower bound of time_ns 395 long long time_ns, 396 const Track*, 397 const CuePoint*&, 398 const CuePoint::TrackPosition*&) const; 399 400 #if 0 401 bool FindNext( //upper_bound of time_ns 402 long long time_ns, 403 const Track*, 404 const CuePoint*&, 405 const CuePoint::TrackPosition*&) const; 406 #endif 407 408 const CuePoint* GetFirst() const; 409 const CuePoint* GetLast() const; 410 411 const CuePoint* GetNext(const CuePoint*) const; 412 413 const BlockEntry* GetBlock( 414 const CuePoint*, 415 const CuePoint::TrackPosition*) const; 416 417 private: 418 void Init() const; 419 bool LoadCuePoint() const; 420 void PreloadCuePoint(size_t&, long long) const; 421 422 mutable CuePoint** m_cue_points; 423 mutable size_t m_count; 424 mutable size_t m_preload_count; 425 mutable long long m_pos; 426 427 }; 428 429 430 class Cluster 431 { 432 Cluster(const Cluster&); 433 Cluster& operator=(const Cluster&); 434 435 public: 436 Segment* const m_pSegment; 437 438 public: 439 static Cluster* Parse(Segment*, long, long long off); 440 441 Cluster(); //EndOfStream 442 ~Cluster(); 443 444 bool EOS() const; 445 446 long long GetTimeCode(); //absolute, but not scaled 447 long long GetTime(); //absolute, and scaled (nanosecond units) 448 long long GetFirstTime(); //time (ns) of first (earliest) block 449 long long GetLastTime(); //time (ns) of last (latest) block 450 451 const BlockEntry* GetFirst(); 452 const BlockEntry* GetLast(); 453 const BlockEntry* GetNext(const BlockEntry*) const; 454 const BlockEntry* GetEntry(const Track*); 455 const BlockEntry* GetEntry( 456 const CuePoint&, 457 const CuePoint::TrackPosition&); 458 const BlockEntry* GetMaxKey(const VideoTrack*); 459 460 protected: 461 Cluster(Segment*, long, long long off); 462 463 public: 464 //TODO: these should all be private, with public selector functions 465 long m_index; 466 long long m_pos; 467 long long m_size; 468 469 private: 470 long long m_timecode; 471 BlockEntry** m_entries; 472 size_t m_entriesCount; 473 474 void Load(); 475 void LoadBlockEntries(); 476 void ParseBlockGroup(long long, long long, size_t); 477 void ParseSimpleBlock(long long, long long, size_t); 478 479 }; 480 481 482 class Segment 483 { 484 friend class Cues; 485 486 Segment(const Segment&); 487 Segment& operator=(const Segment&); 488 489 private: 490 Segment(IMkvReader*, long long pos, long long size); 491 492 public: 493 IMkvReader* const m_pReader; 494 const long long m_start; //posn of segment payload 495 const long long m_size; //size of segment payload 496 Cluster m_eos; //TODO: make private? 497 498 static long long CreateInstance(IMkvReader*, long long, Segment*&); 499 ~Segment(); 500 501 long Load(); //loads headers and all clusters 502 503 //for incremental loading (splitter) 504 long long Unparsed() const; 505 long long ParseHeaders(); //stops when first cluster is found 506 long LoadCluster(); //loads one cluster 507 508 #if 0 509 //This pair parses one cluster, but only changes the state of the 510 //segment object when the cluster is actually added to the index. 511 long ParseCluster(Cluster*&, long long& newpos) const; 512 bool AddCluster(Cluster*, long long); 513 #endif 514 515 Tracks* GetTracks() const; 516 const SegmentInfo* GetInfo() const; 517 const Cues* GetCues() const; 518 519 long long GetDuration() const; 520 521 unsigned long GetCount() const; 522 Cluster* GetFirst(); 523 Cluster* GetLast(); 524 Cluster* GetNext(const Cluster*); 525 526 Cluster* FindCluster(long long time_nanoseconds); 527 const BlockEntry* Seek(long long time_nanoseconds, const Track*); 528 529 private: 530 531 long long m_pos; //absolute file posn; what has been consumed so far 532 SegmentInfo* m_pInfo; 533 Tracks* m_pTracks; 534 Cues* m_pCues; 535 Cluster** m_clusters; 536 long m_clusterCount; //number of entries for which m_index >= 0 537 long m_clusterPreloadCount; //number of entries for which m_index < 0 538 long m_clusterSize; //array size 539 540 void AppendCluster(Cluster*); 541 void PreloadCluster(Cluster*, ptrdiff_t); 542 543 void ParseSeekHead(long long pos, long long size); 544 void ParseSeekEntry(long long pos, long long size); 545 void ParseCues(long long); 546 547 const BlockEntry* GetBlock( 548 const CuePoint&, 549 const CuePoint::TrackPosition&); 550 551 }; 552 553 554 } //end namespace mkvparser 555 556 #endif //MKVPARSER_HPP 557