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
LoadCluster()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