• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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