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#include <cstddef>
15
16namespace mkvparser
17{
18
19const int E_FILE_FORMAT_INVALID = -2;
20const int E_BUFFER_NOT_FULL = -3;
21
22class IMkvReader
23{
24public:
25    virtual int Read(long long pos, long len, unsigned char* buf) = 0;
26    virtual int Length(long long* total, long long* available) = 0;
27protected:
28    virtual ~IMkvReader();
29};
30
31long long GetUIntLength(IMkvReader*, long long, long&);
32long long ReadUInt(IMkvReader*, long long, long&);
33long long UnserializeUInt(IMkvReader*, long long pos, long long size);
34
35long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);
36long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);
37
38long UnserializeString(
39        IMkvReader*,
40        long long pos,
41        long long size,
42        char*& str);
43
44long ParseElementHeader(
45    IMkvReader* pReader,
46    long long& pos,  //consume id and size fields
47    long long stop,  //if you know size of element's parent
48    long long& id,
49    long long& size);
50
51bool Match(IMkvReader*, long long&, unsigned long, long long&);
52bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
53
54void GetVersion(int& major, int& minor, int& build, int& revision);
55
56struct EBMLHeader
57{
58    EBMLHeader();
59    ~EBMLHeader();
60    long long m_version;
61    long long m_readVersion;
62    long long m_maxIdLength;
63    long long m_maxSizeLength;
64    char* m_docType;
65    long long m_docTypeVersion;
66    long long m_docTypeReadVersion;
67
68    long long Parse(IMkvReader*, long long&);
69    void Init();
70};
71
72
73class Segment;
74class Track;
75class Cluster;
76
77class Block
78{
79    Block(const Block&);
80    Block& operator=(const Block&);
81
82public:
83    const long long m_start;
84    const long long m_size;
85
86    Block(long long start, long long size);
87    ~Block();
88
89    long Parse(IMkvReader*);
90
91    long long GetTrackNumber() const;
92    long long GetTimeCode(const Cluster*) const;  //absolute, but not scaled
93    long long GetTime(const Cluster*) const;      //absolute, and scaled (ns)
94    bool IsKey() const;
95    void SetKey(bool);
96    bool IsInvisible() const;
97
98    enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml };
99    Lacing GetLacing() const;
100
101    int GetFrameCount() const;  //to index frames: [0, count)
102
103    struct Frame
104    {
105        long long pos;  //absolute offset
106        long len;
107
108        long Read(IMkvReader*, unsigned char*) const;
109    };
110
111    const Frame& GetFrame(int frame_index) const;
112
113private:
114    long long m_track;   //Track::Number()
115    short m_timecode;  //relative to cluster
116    unsigned char m_flags;
117
118    Frame* m_frames;
119    int m_frame_count;
120
121};
122
123
124class BlockEntry
125{
126    BlockEntry(const BlockEntry&);
127    BlockEntry& operator=(const BlockEntry&);
128
129protected:
130    BlockEntry(Cluster*, long index);
131
132public:
133    virtual ~BlockEntry();
134
135    bool EOS() const;
136    const Cluster* GetCluster() const;
137    long GetIndex() const;
138    virtual const Block* GetBlock() const = 0;
139
140    enum Kind { kBlockEOS, kBlockSimple, kBlockGroup };
141    virtual Kind GetKind() const = 0;
142
143protected:
144    Cluster* const m_pCluster;
145    const long m_index;
146
147};
148
149
150class SimpleBlock : public BlockEntry
151{
152    SimpleBlock(const SimpleBlock&);
153    SimpleBlock& operator=(const SimpleBlock&);
154
155public:
156    SimpleBlock(Cluster*, long index, long long start, long long size);
157    long Parse();
158
159    Kind GetKind() const;
160    const Block* GetBlock() const;
161
162protected:
163    Block m_block;
164
165};
166
167
168class BlockGroup : public BlockEntry
169{
170    BlockGroup(const BlockGroup&);
171    BlockGroup& operator=(const BlockGroup&);
172
173public:
174    BlockGroup(
175        Cluster*,
176        long index,
177        long long block_start, //absolute pos of block's payload
178        long long block_size,  //size of block's payload
179        long long prev,
180        long long next,
181        long long duration);
182
183    long Parse();
184
185    Kind GetKind() const;
186    const Block* GetBlock() const;
187
188    long long GetPrevTimeCode() const;  //relative to block's time
189    long long GetNextTimeCode() const;  //as above
190    long long GetDuration() const;
191
192private:
193    Block m_block;
194    const long long m_prev;
195    const long long m_next;
196    const long long m_duration;
197
198};
199
200///////////////////////////////////////////////////////////////
201// ContentEncoding element
202// Elements used to describe if the track data has been encrypted or
203// compressed with zlib or header stripping.
204class ContentEncoding {
205public:
206    ContentEncoding();
207    ~ContentEncoding();
208
209    // ContentCompression element names
210    struct ContentCompression {
211        ContentCompression();
212        ~ContentCompression();
213
214        unsigned long long algo;
215        unsigned char* settings;
216    };
217
218    // ContentEncryption element names
219    struct ContentEncryption {
220        ContentEncryption();
221        ~ContentEncryption();
222
223        unsigned long long algo;
224        unsigned char* key_id;
225        long long key_id_len;
226        unsigned char* signature;
227        long long signature_len;
228        unsigned char* sig_key_id;
229        long long sig_key_id_len;
230        unsigned long long sig_algo;
231        unsigned long long sig_hash_algo;
232    };
233
234    // Returns ContentCompression represented by |idx|. Returns NULL if |idx|
235    // is out of bounds.
236    const ContentCompression* GetCompressionByIndex(unsigned long idx) const;
237
238    // Returns number of ContentCompression elements in this ContentEncoding
239    // element.
240    unsigned long GetCompressionCount() const;
241
242    // Returns ContentEncryption represented by |idx|. Returns NULL if |idx|
243    // is out of bounds.
244    const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const;
245
246    // Returns number of ContentEncryption elements in this ContentEncoding
247    // element.
248    unsigned long GetEncryptionCount() const;
249
250    // Parses the ContentEncoding element from |pReader|. |start| is the
251    // starting offset of the ContentEncoding payload. |size| is the size in
252    // bytes of the ContentEncoding payload. Returns true on success.
253    bool ParseContentEncodingEntry(long long start,
254                                   long long size,
255                                   IMkvReader* const pReader);
256
257    // Parses the ContentEncryption element from |pReader|. |start| is the
258    // starting offset of the ContentEncryption payload. |size| is the size in
259    // bytes of the ContentEncryption payload. |encryption| is where the parsed
260    // values will be stored.
261    void ParseEncryptionEntry(long long start,
262                              long long size,
263                              IMkvReader* const pReader,
264                              ContentEncryption* const encryption);
265
266    unsigned long long encoding_order() const { return encoding_order_; }
267    unsigned long long encoding_scope() const { return encoding_scope_; }
268    unsigned long long encoding_type() const { return encoding_type_; }
269
270private:
271    // Member variables for list of ContentCompression elements.
272    ContentCompression** compression_entries_;
273    ContentCompression** compression_entries_end_;
274
275    // Member variables for list of ContentEncryption elements.
276    ContentEncryption** encryption_entries_;
277    ContentEncryption** encryption_entries_end_;
278
279    // ContentEncoding element names
280    unsigned long long encoding_order_;
281    unsigned long long encoding_scope_;
282    unsigned long long encoding_type_;
283
284    // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
285    ContentEncoding(const ContentEncoding&);
286    ContentEncoding& operator=(const ContentEncoding&);
287};
288
289class Track
290{
291    Track(const Track&);
292    Track& operator=(const Track&);
293
294public:
295    enum Type { kVideo = 1, kAudio = 2 };
296
297    Segment* const m_pSegment;
298    const long long m_element_start;
299    const long long m_element_size;
300    virtual ~Track();
301
302    long GetType() const;
303    long GetNumber() const;
304    unsigned long long GetUid() const;
305    const char* GetNameAsUTF8() const;
306    const char* GetCodecNameAsUTF8() const;
307    const char* GetCodecId() const;
308    const unsigned char* GetCodecPrivate(size_t&) const;
309    bool GetLacing() const;
310
311    const BlockEntry* GetEOS() const;
312
313    struct Settings
314    {
315        long long start;
316        long long size;
317    };
318
319    class Info
320    {
321    public:
322        Info();
323        ~Info();
324        int Copy(Info&) const;
325        void Clear();
326    private:
327        Info(const Info&);
328        Info& operator=(const Info&);
329    public:
330        long type;
331        long number;
332        unsigned long long uid;
333        char* nameAsUTF8;
334        char* codecId;
335        char* codecNameAsUTF8;
336        unsigned char* codecPrivate;
337        size_t codecPrivateSize;
338        bool lacing;
339        Settings settings;
340    private:
341        int CopyStr(char* Info::*str, Info&) const;
342    };
343
344    long GetFirst(const BlockEntry*&) const;
345    long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
346    virtual bool VetEntry(const BlockEntry*) const = 0;
347    virtual long Seek(long long time_ns, const BlockEntry*&) const = 0;
348
349    const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
350    unsigned long GetContentEncodingCount() const;
351
352    void ParseContentEncodingsEntry(long long start, long long size);
353
354protected:
355    Track(
356        Segment*,
357        long long element_start,
358        long long element_size);
359
360    Info m_info;
361
362    class EOSBlock : public BlockEntry
363    {
364    public:
365        EOSBlock();
366
367        Kind GetKind() const;
368        const Block* GetBlock() const;
369    };
370
371    EOSBlock m_eos;
372
373private:
374    ContentEncoding** content_encoding_entries_;
375    ContentEncoding** content_encoding_entries_end_;
376};
377
378
379class VideoTrack : public Track
380{
381    VideoTrack(const VideoTrack&);
382    VideoTrack& operator=(const VideoTrack&);
383
384    VideoTrack(
385        Segment*,
386        long long element_start,
387        long long element_size);
388
389public:
390    static long Parse(
391        Segment*,
392        const Info&,
393        long long element_start,
394        long long element_size,
395        VideoTrack*&);
396
397    long long GetWidth() const;
398    long long GetHeight() const;
399    double GetFrameRate() const;
400
401    bool VetEntry(const BlockEntry*) const;
402    long Seek(long long time_ns, const BlockEntry*&) const;
403
404private:
405    long long m_width;
406    long long m_height;
407    double m_rate;
408
409};
410
411
412class AudioTrack : public Track
413{
414    AudioTrack(const AudioTrack&);
415    AudioTrack& operator=(const AudioTrack&);
416
417    AudioTrack(
418        Segment*,
419        long long element_start,
420        long long element_size);
421public:
422    static long Parse(
423        Segment*,
424        const Info&,
425        long long element_start,
426        long long element_size,
427        AudioTrack*&);
428
429    double GetSamplingRate() const;
430    long long GetChannels() const;
431    long long GetBitDepth() const;
432    bool VetEntry(const BlockEntry*) const;
433    long Seek(long long time_ns, const BlockEntry*&) const;
434
435private:
436    double m_rate;
437    long long m_channels;
438    long long m_bitDepth;
439};
440
441
442class Tracks
443{
444    Tracks(const Tracks&);
445    Tracks& operator=(const Tracks&);
446
447public:
448    Segment* const m_pSegment;
449    const long long m_start;
450    const long long m_size;
451    const long long m_element_start;
452    const long long m_element_size;
453
454    Tracks(
455        Segment*,
456        long long start,
457        long long size,
458        long long element_start,
459        long long element_size);
460
461    ~Tracks();
462
463    long Parse();
464
465    unsigned long GetTracksCount() const;
466
467    const Track* GetTrackByNumber(long tn) const;
468    const Track* GetTrackByIndex(unsigned long idx) const;
469
470private:
471    Track** m_trackEntries;
472    Track** m_trackEntriesEnd;
473
474    long ParseTrackEntry(
475        long long payload_start,
476        long long payload_size,
477        long long element_start,
478        long long element_size,
479        Track*&) const;
480
481};
482
483
484class SegmentInfo
485{
486    SegmentInfo(const SegmentInfo&);
487    SegmentInfo& operator=(const SegmentInfo&);
488
489public:
490    Segment* const m_pSegment;
491    const long long m_start;
492    const long long m_size;
493    const long long m_element_start;
494    const long long m_element_size;
495
496    SegmentInfo(
497        Segment*,
498        long long start,
499        long long size,
500        long long element_start,
501        long long element_size);
502
503    ~SegmentInfo();
504
505    long Parse();
506
507    long long GetTimeCodeScale() const;
508    long long GetDuration() const;  //scaled
509    const char* GetMuxingAppAsUTF8() const;
510    const char* GetWritingAppAsUTF8() const;
511    const char* GetTitleAsUTF8() const;
512
513private:
514    long long m_timecodeScale;
515    double m_duration;
516    char* m_pMuxingAppAsUTF8;
517    char* m_pWritingAppAsUTF8;
518    char* m_pTitleAsUTF8;
519};
520
521
522class SeekHead
523{
524    SeekHead(const SeekHead&);
525    SeekHead& operator=(const SeekHead&);
526
527public:
528    Segment* const m_pSegment;
529    const long long m_start;
530    const long long m_size;
531    const long long m_element_start;
532    const long long m_element_size;
533
534    SeekHead(
535        Segment*,
536        long long start,
537        long long size,
538        long long element_start,
539        long long element_size);
540
541    ~SeekHead();
542
543    long Parse();
544
545    struct Entry
546    {
547        //the SeekHead entry payload
548        long long id;
549        long long pos;
550
551        //absolute pos of SeekEntry ID
552        long long element_start;
553
554        //SeekEntry ID size + size size + payload
555        long long element_size;
556    };
557
558    int GetCount() const;
559    const Entry* GetEntry(int idx) const;
560
561    struct VoidElement
562    {
563        //absolute pos of Void ID
564        long long element_start;
565
566        //ID size + size size + payload size
567        long long element_size;
568    };
569
570    int GetVoidElementCount() const;
571    const VoidElement* GetVoidElement(int idx) const;
572
573private:
574    Entry* m_entries;
575    int m_entry_count;
576
577    VoidElement* m_void_elements;
578    int m_void_element_count;
579
580    static bool ParseEntry(
581        IMkvReader*,
582        long long pos,  //payload
583        long long size,
584        Entry*);
585
586};
587
588class Cues;
589class CuePoint
590{
591    friend class Cues;
592
593    CuePoint(long, long long);
594    ~CuePoint();
595
596    CuePoint(const CuePoint&);
597    CuePoint& operator=(const CuePoint&);
598
599public:
600    long long m_element_start;
601    long long m_element_size;
602
603    void Load(IMkvReader*);
604
605    long long GetTimeCode() const;      //absolute but unscaled
606    long long GetTime(const Segment*) const;  //absolute and scaled (ns units)
607
608    struct TrackPosition
609    {
610        long long m_track;
611        long long m_pos;  //of cluster
612        long long m_block;
613        //codec_state  //defaults to 0
614        //reference = clusters containing req'd referenced blocks
615        //  reftime = timecode of the referenced block
616
617        void Parse(IMkvReader*, long long, long long);
618    };
619
620    const TrackPosition* Find(const Track*) const;
621
622private:
623    const long m_index;
624    long long m_timecode;
625    TrackPosition* m_track_positions;
626    size_t m_track_positions_count;
627
628};
629
630
631class Cues
632{
633    friend class Segment;
634
635    Cues(
636        Segment*,
637        long long start,
638        long long size,
639        long long element_start,
640        long long element_size);
641    ~Cues();
642
643    Cues(const Cues&);
644    Cues& operator=(const Cues&);
645
646public:
647    Segment* const m_pSegment;
648    const long long m_start;
649    const long long m_size;
650    const long long m_element_start;
651    const long long m_element_size;
652
653    bool Find(  //lower bound of time_ns
654        long long time_ns,
655        const Track*,
656        const CuePoint*&,
657        const CuePoint::TrackPosition*&) const;
658
659#if 0
660    bool FindNext(  //upper_bound of time_ns
661        long long time_ns,
662        const Track*,
663        const CuePoint*&,
664        const CuePoint::TrackPosition*&) const;
665#endif
666
667    const CuePoint* GetFirst() const;
668    const CuePoint* GetLast() const;
669    const CuePoint* GetNext(const CuePoint*) const;
670
671    const BlockEntry* GetBlock(
672                        const CuePoint*,
673                        const CuePoint::TrackPosition*) const;
674
675    bool LoadCuePoint() const;
676    long GetCount() const;  //loaded only
677    //long GetTotal() const;  //loaded + preloaded
678    bool DoneParsing() const;
679
680private:
681    void Init() const;
682    void PreloadCuePoint(long&, long long) const;
683
684    mutable CuePoint** m_cue_points;
685    mutable long m_count;
686    mutable long m_preload_count;
687    mutable long long m_pos;
688
689};
690
691
692class Cluster
693{
694    friend class Segment;
695
696    Cluster(const Cluster&);
697    Cluster& operator=(const Cluster&);
698
699public:
700    Segment* const m_pSegment;
701
702public:
703    static Cluster* Create(
704        Segment*,
705        long index,       //index in segment
706        long long off);   //offset relative to segment
707        //long long element_size);
708
709    Cluster();  //EndOfStream
710    ~Cluster();
711
712    bool EOS() const;
713
714    long long GetTimeCode() const;   //absolute, but not scaled
715    long long GetTime() const;       //absolute, and scaled (nanosecond units)
716    long long GetFirstTime() const;  //time (ns) of first (earliest) block
717    long long GetLastTime() const;   //time (ns) of last (latest) block
718
719    long GetFirst(const BlockEntry*&) const;
720    long GetLast(const BlockEntry*&) const;
721    long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
722
723    const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
724    const BlockEntry* GetEntry(
725        const CuePoint&,
726        const CuePoint::TrackPosition&) const;
727    //const BlockEntry* GetMaxKey(const VideoTrack*) const;
728
729//    static bool HasBlockEntries(const Segment*, long long);
730
731    static long HasBlockEntries(
732            const Segment*,
733            long long idoff,
734            long long& pos,
735            long& size);
736
737    long GetEntryCount() const;
738
739    long Load(long long& pos, long& size) const;
740
741    long Parse(long long& pos, long& size) const;
742    long GetEntry(long index, const mkvparser::BlockEntry*&) const;
743
744protected:
745    Cluster(
746        Segment*,
747        long index,
748        long long element_start);
749        //long long element_size);
750
751public:
752    const long long m_element_start;
753    long long GetPosition() const;  //offset relative to segment
754
755    long GetIndex() const;
756    long long GetElementSize() const;
757    //long long GetPayloadSize() const;
758
759    //long long Unparsed() const;
760
761private:
762    long m_index;
763    mutable long long m_pos;
764    //mutable long long m_size;
765    mutable long long m_element_size;
766    mutable long long m_timecode;
767    mutable BlockEntry** m_entries;
768    mutable long m_entries_size;
769    mutable long m_entries_count;
770
771    long ParseSimpleBlock(long long, long long&, long&);
772    long ParseBlockGroup(long long, long long&, long&);
773
774    long CreateBlock(long long id, long long pos, long long size);
775    long CreateBlockGroup(long long, long long);
776    long CreateSimpleBlock(long long, long long);
777
778};
779
780
781class Segment
782{
783    friend class Cues;
784    friend class VideoTrack;
785    friend class AudioTrack;
786
787    Segment(const Segment&);
788    Segment& operator=(const Segment&);
789
790private:
791    Segment(
792        IMkvReader*,
793        long long elem_start,
794        //long long elem_size,
795        long long pos,
796        long long size);
797
798public:
799    IMkvReader* const m_pReader;
800    const long long m_element_start;
801    //const long long m_element_size;
802    const long long m_start;  //posn of segment payload
803    const long long m_size;   //size of segment payload
804    Cluster m_eos;  //TODO: make private?
805
806    static long long CreateInstance(IMkvReader*, long long, Segment*&);
807    ~Segment();
808
809    long Load();  //loads headers and all clusters
810
811    //for incremental loading
812    //long long Unparsed() const;
813    bool DoneParsing() const;
814    long long ParseHeaders();  //stops when first cluster is found
815    //long FindNextCluster(long long& pos, long& size) const;
816    long LoadCluster(long long& pos, long& size);  //load one cluster
817    long LoadCluster();
818
819    long ParseNext(
820            const Cluster* pCurr,
821            const Cluster*& pNext,
822            long long& pos,
823            long& size);
824
825#if 0
826    //This pair parses one cluster, but only changes the state of the
827    //segment object when the cluster is actually added to the index.
828    long ParseCluster(long long& cluster_pos, long long& new_pos) const;
829    bool AddCluster(long long cluster_pos, long long new_pos);
830#endif
831
832    const SeekHead* GetSeekHead() const;
833    const Tracks* GetTracks() const;
834    const SegmentInfo* GetInfo() const;
835    const Cues* GetCues() const;
836
837    long long GetDuration() const;
838
839    unsigned long GetCount() const;
840    const Cluster* GetFirst() const;
841    const Cluster* GetLast() const;
842    const Cluster* GetNext(const Cluster*);
843
844    const Cluster* FindCluster(long long time_nanoseconds) const;
845    //const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
846
847    const Cluster* FindOrPreloadCluster(long long pos);
848
849    long ParseCues(
850        long long cues_off,  //offset relative to start of segment
851        long long& parse_pos,
852        long& parse_len);
853
854private:
855
856    long long m_pos;  //absolute file posn; what has been consumed so far
857    Cluster* m_pUnknownSize;
858
859    SeekHead* m_pSeekHead;
860    SegmentInfo* m_pInfo;
861    Tracks* m_pTracks;
862    Cues* m_pCues;
863    Cluster** m_clusters;
864    long m_clusterCount;         //number of entries for which m_index >= 0
865    long m_clusterPreloadCount;  //number of entries for which m_index < 0
866    long m_clusterSize;          //array size
867
868    long DoLoadCluster(long long&, long&);
869    long DoLoadClusterUnknownSize(long long&, long&);
870    long DoParseNext(const Cluster*&, long long&, long&);
871
872    void AppendCluster(Cluster*);
873    void PreloadCluster(Cluster*, ptrdiff_t);
874
875    //void ParseSeekHead(long long pos, long long size);
876    //void ParseSeekEntry(long long pos, long long size);
877    //void ParseCues(long long);
878
879    const BlockEntry* GetBlock(
880        const CuePoint&,
881        const CuePoint::TrackPosition&);
882
883};
884
885}  //end namespace mkvparser
886
887inline long mkvparser::Segment::LoadCluster()
888{
889    long long pos;
890    long size;
891
892    return LoadCluster(pos, size);
893}
894
895#endif  //MKVPARSER_HPP
896