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    long GetIndex() const;
608
609    struct TrackPosition
610    {
611        long long m_track;
612        long long m_pos;  //of cluster
613        long long m_block;
614        //codec_state  //defaults to 0
615        //reference = clusters containing req'd referenced blocks
616        //  reftime = timecode of the referenced block
617
618        void Parse(IMkvReader*, long long, long long);
619    };
620
621    const TrackPosition* Find(const Track*) const;
622
623private:
624    const long m_index;
625    long long m_timecode;
626    TrackPosition* m_track_positions;
627    size_t m_track_positions_count;
628
629};
630
631
632class Cues
633{
634    friend class Segment;
635
636    Cues(
637        Segment*,
638        long long start,
639        long long size,
640        long long element_start,
641        long long element_size);
642    ~Cues();
643
644    Cues(const Cues&);
645    Cues& operator=(const Cues&);
646
647public:
648    Segment* const m_pSegment;
649    const long long m_start;
650    const long long m_size;
651    const long long m_element_start;
652    const long long m_element_size;
653
654    bool Find(  //lower bound of time_ns
655        long long time_ns,
656        const Track*,
657        const CuePoint*&,
658        const CuePoint::TrackPosition*&) const;
659
660#if 0
661    bool FindNext(  //upper_bound of time_ns
662        long long time_ns,
663        const Track*,
664        const CuePoint*&,
665        const CuePoint::TrackPosition*&) const;
666#endif
667
668    const CuePoint* GetFirst() const;
669    const CuePoint* GetLast() const;
670    const CuePoint* GetNext(const CuePoint*) const;
671
672    const BlockEntry* GetBlock(
673                        const CuePoint*,
674                        const CuePoint::TrackPosition*) const;
675
676    bool LoadCuePoint() const;
677    long GetCount() const;  //loaded only
678    //long GetTotal() const;  //loaded + preloaded
679    bool DoneParsing() const;
680
681private:
682    void Init() const;
683    void PreloadCuePoint(long&, long long) const;
684
685    mutable CuePoint** m_cue_points;
686    mutable long m_count;
687    mutable long m_preload_count;
688    mutable long long m_pos;
689
690};
691
692
693class Cluster
694{
695    friend class Segment;
696
697    Cluster(const Cluster&);
698    Cluster& operator=(const Cluster&);
699
700public:
701    Segment* const m_pSegment;
702
703public:
704    static Cluster* Create(
705        Segment*,
706        long index,       //index in segment
707        long long off);   //offset relative to segment
708        //long long element_size);
709
710    Cluster();  //EndOfStream
711    ~Cluster();
712
713    bool EOS() const;
714
715    long long GetTimeCode() const;   //absolute, but not scaled
716    long long GetTime() const;       //absolute, and scaled (nanosecond units)
717    long long GetFirstTime() const;  //time (ns) of first (earliest) block
718    long long GetLastTime() const;   //time (ns) of last (latest) block
719
720    long GetFirst(const BlockEntry*&) const;
721    long GetLast(const BlockEntry*&) const;
722    long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
723
724    const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
725    const BlockEntry* GetEntry(
726        const CuePoint&,
727        const CuePoint::TrackPosition&) const;
728    //const BlockEntry* GetMaxKey(const VideoTrack*) const;
729
730//    static bool HasBlockEntries(const Segment*, long long);
731
732    static long HasBlockEntries(
733            const Segment*,
734            long long idoff,
735            long long& pos,
736            long& size);
737
738    long GetEntryCount() const;
739
740    long Load(long long& pos, long& size) const;
741
742    long Parse(long long& pos, long& size) const;
743    long GetEntry(long index, const mkvparser::BlockEntry*&) const;
744
745protected:
746    Cluster(
747        Segment*,
748        long index,
749        long long element_start);
750        //long long element_size);
751
752public:
753    const long long m_element_start;
754    long long GetPosition() const;  //offset relative to segment
755
756    long GetIndex() const;
757    long long GetElementSize() const;
758    //long long GetPayloadSize() const;
759
760    //long long Unparsed() const;
761
762private:
763    long m_index;
764    mutable long long m_pos;
765    //mutable long long m_size;
766    mutable long long m_element_size;
767    mutable long long m_timecode;
768    mutable BlockEntry** m_entries;
769    mutable long m_entries_size;
770    mutable long m_entries_count;
771
772    long ParseSimpleBlock(long long, long long&, long&);
773    long ParseBlockGroup(long long, long long&, long&);
774
775    long CreateBlock(long long id, long long pos, long long size);
776    long CreateBlockGroup(long long, long long);
777    long CreateSimpleBlock(long long, long long);
778
779};
780
781
782class Segment
783{
784    friend class Cues;
785    friend class VideoTrack;
786    friend class AudioTrack;
787
788    Segment(const Segment&);
789    Segment& operator=(const Segment&);
790
791private:
792    Segment(
793        IMkvReader*,
794        long long elem_start,
795        //long long elem_size,
796        long long pos,
797        long long size);
798
799public:
800    IMkvReader* const m_pReader;
801    const long long m_element_start;
802    //const long long m_element_size;
803    const long long m_start;  //posn of segment payload
804    const long long m_size;   //size of segment payload
805    Cluster m_eos;  //TODO: make private?
806
807    static long long CreateInstance(IMkvReader*, long long, Segment*&);
808    ~Segment();
809
810    long Load();  //loads headers and all clusters
811
812    //for incremental loading
813    //long long Unparsed() const;
814    bool DoneParsing() const;
815    long long ParseHeaders();  //stops when first cluster is found
816    //long FindNextCluster(long long& pos, long& size) const;
817    long LoadCluster(long long& pos, long& size);  //load one cluster
818    long LoadCluster();
819
820    long ParseNext(
821            const Cluster* pCurr,
822            const Cluster*& pNext,
823            long long& pos,
824            long& size);
825
826#if 0
827    //This pair parses one cluster, but only changes the state of the
828    //segment object when the cluster is actually added to the index.
829    long ParseCluster(long long& cluster_pos, long long& new_pos) const;
830    bool AddCluster(long long cluster_pos, long long new_pos);
831#endif
832
833    const SeekHead* GetSeekHead() const;
834    const Tracks* GetTracks() const;
835    const SegmentInfo* GetInfo() const;
836    const Cues* GetCues() const;
837
838    long long GetDuration() const;
839
840    unsigned long GetCount() const;
841    const Cluster* GetFirst() const;
842    const Cluster* GetLast() const;
843    const Cluster* GetNext(const Cluster*);
844
845    const Cluster* FindCluster(long long time_nanoseconds) const;
846    //const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
847
848    const Cluster* FindOrPreloadCluster(long long pos);
849
850    long ParseCues(
851        long long cues_off,  //offset relative to start of segment
852        long long& parse_pos,
853        long& parse_len);
854
855private:
856
857    long long m_pos;  //absolute file posn; what has been consumed so far
858    Cluster* m_pUnknownSize;
859
860    SeekHead* m_pSeekHead;
861    SegmentInfo* m_pInfo;
862    Tracks* m_pTracks;
863    Cues* m_pCues;
864    Cluster** m_clusters;
865    long m_clusterCount;         //number of entries for which m_index >= 0
866    long m_clusterPreloadCount;  //number of entries for which m_index < 0
867    long m_clusterSize;          //array size
868
869    long DoLoadCluster(long long&, long&);
870    long DoLoadClusterUnknownSize(long long&, long&);
871    long DoParseNext(const Cluster*&, long long&, long&);
872
873    void AppendCluster(Cluster*);
874    void PreloadCluster(Cluster*, ptrdiff_t);
875
876    //void ParseSeekHead(long long pos, long long size);
877    //void ParseSeekEntry(long long pos, long long size);
878    //void ParseCues(long long);
879
880    const BlockEntry* GetBlock(
881        const CuePoint&,
882        const CuePoint::TrackPosition&);
883
884};
885
886}  //end namespace mkvparser
887
888inline long mkvparser::Segment::LoadCluster()
889{
890    long long pos;
891    long size;
892
893    return LoadCluster(pos, size);
894}
895
896#endif  //MKVPARSER_HPP
897