Home | History | Annotate | Download | only in matroska
      1 #ifndef MKVPARSER_HPP
      2 #define MKVPARSER_HPP
      3 
      4 #include <cstdlib>
      5 #include <cstdio>
      6 
      7 namespace mkvparser
      8 {
      9 
     10 const int E_FILE_FORMAT_INVALID = -2;
     11 const int E_BUFFER_NOT_FULL = -3;
     12 
     13 class IMkvReader
     14 {
     15 public:
     16     virtual int Read(long long position, long length, unsigned char* buffer) = 0;
     17     virtual int Length(long long* total, long long* available) = 0;
     18 protected:
     19     virtual ~IMkvReader();
     20 };
     21 
     22 long long GetUIntLength(IMkvReader*, long long, long&);
     23 long long ReadUInt(IMkvReader*, long long, long&);
     24 long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);
     25 long long UnserializeUInt(IMkvReader*, long long pos, long long size);
     26 float Unserialize4Float(IMkvReader*, long long);
     27 double Unserialize8Double(IMkvReader*, long long);
     28 short Unserialize2SInt(IMkvReader*, long long);
     29 signed char Unserialize1SInt(IMkvReader*, long long);
     30 bool Match(IMkvReader*, long long&, unsigned long, long long&);
     31 bool Match(IMkvReader*, long long&, unsigned long, char*&);
     32 bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&,
     33            size_t *optionalSize = NULL);
     34 bool Match(IMkvReader*, long long&, unsigned long, double&);
     35 bool Match(IMkvReader*, long long&, unsigned long, short&);
     36 
     37 
     38 struct EBMLHeader
     39 {
     40     EBMLHeader();
     41     ~EBMLHeader();
     42     long long m_version;
     43     long long m_readVersion;
     44     long long m_maxIdLength;
     45     long long m_maxSizeLength;
     46     char* m_docType;
     47     long long m_docTypeVersion;
     48     long long m_docTypeReadVersion;
     49 
     50     long long Parse(IMkvReader*, long long&);
     51 };
     52 
     53 
     54 class Segment;
     55 class Track;
     56 class Cluster;
     57 
     58 class Block
     59 {
     60     Block(const Block&);
     61     Block& operator=(const Block&);
     62 
     63 public:
     64     const long long m_start;
     65     const long long m_size;
     66 
     67     Block(long long start, long long size, IMkvReader*);
     68 
     69     unsigned long GetTrackNumber() const;
     70 
     71     long long GetTimeCode(Cluster*) const;  //absolute, but not scaled
     72     long long GetTime(Cluster*) const;      //absolute, and scaled (nanosecond units)
     73     bool IsKey() const;
     74     void SetKey(bool);
     75 
     76     long GetSize() const;
     77     long Read(IMkvReader*, unsigned char*) const;
     78 
     79 private:
     80     long long m_track;   //Track::Number()
     81     short m_timecode;  //relative to cluster
     82     unsigned char m_flags;
     83     long long m_frameOff;
     84     long m_frameSize;
     85 
     86 };
     87 
     88 
     89 class BlockEntry
     90 {
     91     BlockEntry(const BlockEntry&);
     92     BlockEntry& operator=(const BlockEntry&);
     93 
     94 public:
     95     virtual ~BlockEntry();
     96     virtual bool EOS() const = 0;
     97     virtual Cluster* GetCluster() const = 0;
     98     virtual size_t GetIndex() const = 0;
     99     virtual const Block* GetBlock() const = 0;
    100     virtual bool IsBFrame() const = 0;
    101 
    102 protected:
    103     BlockEntry();
    104 
    105 };
    106 
    107 
    108 class SimpleBlock : public BlockEntry
    109 {
    110     SimpleBlock(const SimpleBlock&);
    111     SimpleBlock& operator=(const SimpleBlock&);
    112 
    113 public:
    114     SimpleBlock(Cluster*, size_t, long long start, long long size);
    115 
    116     bool EOS() const;
    117     Cluster* GetCluster() const;
    118     size_t GetIndex() const;
    119     const Block* GetBlock() const;
    120     bool IsBFrame() const;
    121 
    122 protected:
    123     Cluster* const m_pCluster;
    124     const size_t m_index;
    125     Block m_block;
    126 
    127 };
    128 
    129 
    130 class BlockGroup : public BlockEntry
    131 {
    132     BlockGroup(const BlockGroup&);
    133     BlockGroup& operator=(const BlockGroup&);
    134 
    135 public:
    136     BlockGroup(Cluster*, size_t, long long, long long);
    137     ~BlockGroup();
    138 
    139     bool EOS() const;
    140     Cluster* GetCluster() const;
    141     size_t GetIndex() const;
    142     const Block* GetBlock() const;
    143     bool IsBFrame() const;
    144 
    145     short GetPrevTimeCode() const;  //relative to block's time
    146     short GetNextTimeCode() const;  //as above
    147 
    148 protected:
    149     Cluster* const m_pCluster;
    150     const size_t m_index;
    151 
    152 private:
    153     BlockGroup(Cluster*, size_t, unsigned long);
    154     void ParseBlock(long long start, long long size);
    155 
    156     short m_prevTimeCode;
    157     short m_nextTimeCode;
    158 
    159     //TODO: the Matroska spec says you can have multiple blocks within the
    160     //same block group, with blocks ranked by priority (the flag bits).
    161     //For now we just cache a single block.
    162 #if 0
    163     typedef std::deque<Block*> blocks_t;
    164     blocks_t m_blocks;  //In practice should contain only a single element.
    165 #else
    166     Block* m_pBlock;
    167 #endif
    168 
    169 };
    170 
    171 
    172 class Track
    173 {
    174     Track(const Track&);
    175     Track& operator=(const Track&);
    176 
    177 public:
    178     Segment* const m_pSegment;
    179     virtual ~Track();
    180 
    181     long long GetType() const;
    182     unsigned long GetNumber() const;
    183     const char* GetNameAsUTF8() const;
    184     const char* GetCodecNameAsUTF8() const;
    185     const char* GetCodecId() const;
    186     const unsigned char* GetCodecPrivate(
    187             size_t *optionalSize = NULL) const;
    188 
    189     const BlockEntry* GetEOS() const;
    190 
    191     struct Settings
    192     {
    193         long long start;
    194         long long size;
    195     };
    196 
    197     struct Info
    198     {
    199         long long type;
    200         long long number;
    201         long long uid;
    202         char* nameAsUTF8;
    203         char* codecId;
    204         unsigned char* codecPrivate;
    205         size_t codecPrivateSize;
    206         char* codecNameAsUTF8;
    207         Settings settings;
    208         Info();
    209         void Clear();
    210     };
    211 
    212     long GetFirst(const BlockEntry*&) const;
    213     long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
    214     virtual bool VetEntry(const BlockEntry*) const = 0;
    215 
    216 protected:
    217     Track(Segment*, const Info&);
    218     const Info m_info;
    219 
    220     class EOSBlock : public BlockEntry
    221     {
    222     public:
    223         EOSBlock();
    224 
    225         bool EOS() const;
    226         Cluster* GetCluster() const;
    227         size_t GetIndex() const;
    228         const Block* GetBlock() const;
    229         bool IsBFrame() const;
    230     };
    231 
    232     EOSBlock m_eos;
    233 
    234 };
    235 
    236 
    237 class VideoTrack : public Track
    238 {
    239     VideoTrack(const VideoTrack&);
    240     VideoTrack& operator=(const VideoTrack&);
    241 
    242 public:
    243     VideoTrack(Segment*, const Info&);
    244     long long GetWidth() const;
    245     long long GetHeight() const;
    246     double GetFrameRate() const;
    247 
    248     bool VetEntry(const BlockEntry*) const;
    249 
    250 private:
    251     long long m_width;
    252     long long m_height;
    253     double m_rate;
    254 
    255 };
    256 
    257 
    258 class AudioTrack : public Track
    259 {
    260     AudioTrack(const AudioTrack&);
    261     AudioTrack& operator=(const AudioTrack&);
    262 
    263 public:
    264     AudioTrack(Segment*, const Info&);
    265     double GetSamplingRate() const;
    266     long long GetChannels() const;
    267     long long GetBitDepth() const;
    268     bool VetEntry(const BlockEntry*) const;
    269 
    270 private:
    271     double m_rate;
    272     long long m_channels;
    273     long long m_bitDepth;
    274 };
    275 
    276 
    277 class Tracks
    278 {
    279     Tracks(const Tracks&);
    280     Tracks& operator=(const Tracks&);
    281 
    282 public:
    283     Segment* const m_pSegment;
    284     const long long m_start;
    285     const long long m_size;
    286 
    287     Tracks(Segment*, long long start, long long size);
    288     virtual ~Tracks();
    289 
    290     Track* GetTrackByNumber(unsigned long tn) const;
    291     Track* GetTrackByIndex(unsigned long idx) const;
    292 
    293 private:
    294     Track** m_trackEntries;
    295     Track** m_trackEntriesEnd;
    296 
    297     void ParseTrackEntry(long long, long long, Track*&);
    298 
    299 public:
    300     unsigned long GetTracksCount() const;
    301 };
    302 
    303 
    304 class SegmentInfo
    305 {
    306     SegmentInfo(const SegmentInfo&);
    307     SegmentInfo& operator=(const SegmentInfo&);
    308 
    309 public:
    310     Segment* const m_pSegment;
    311     const long long m_start;
    312     const long long m_size;
    313 
    314     SegmentInfo(Segment*, long long start, long long size);
    315     ~SegmentInfo();
    316     long long GetTimeCodeScale() const;
    317     long long GetDuration() const;  //scaled
    318     const char* GetMuxingAppAsUTF8() const;
    319     const char* GetWritingAppAsUTF8() const;
    320     const char* GetTitleAsUTF8() const;
    321 
    322 private:
    323     long long m_timecodeScale;
    324     double m_duration;
    325     char* m_pMuxingAppAsUTF8;
    326     char* m_pWritingAppAsUTF8;
    327     char* m_pTitleAsUTF8;
    328 };
    329 
    330 
    331 class Cluster
    332 {
    333     Cluster(const Cluster&);
    334     Cluster& operator=(const Cluster&);
    335 
    336 public:
    337     Segment* const m_pSegment;
    338     const size_t m_index;
    339 
    340 public:
    341     static Cluster* Parse(Segment*, size_t, long long off);
    342 
    343     Cluster();  //EndOfStream
    344     ~Cluster();
    345 
    346     bool EOS() const;
    347 
    348     long long GetTimeCode();  //absolute, but not scaled
    349     long long GetTime();      //absolute, and scaled (nanosecond units)
    350 
    351     const BlockEntry* GetFirst();
    352     const BlockEntry* GetLast();
    353     const BlockEntry* GetNext(const BlockEntry*) const;
    354     const BlockEntry* GetEntry(const Track*);
    355 protected:
    356     Cluster(Segment*, size_t, long long off);
    357 
    358 private:
    359     long long m_start;
    360     long long m_size;
    361     long long m_timecode;
    362     BlockEntry** m_pEntries;
    363     size_t m_entriesCount;
    364 
    365     void Load();
    366     void LoadBlockEntries();
    367     void ParseBlockGroup(long long, long long, size_t);
    368     void ParseSimpleBlock(long long, long long, size_t);
    369 
    370 };
    371 
    372 
    373 class Segment
    374 {
    375     Segment(const Segment&);
    376     Segment& operator=(const Segment&);
    377 
    378 private:
    379     Segment(IMkvReader*, long long pos, long long size);
    380 
    381 public:
    382     IMkvReader* const m_pReader;
    383     const long long m_start;  //posn of segment payload
    384     const long long m_size;   //size of segment payload
    385     Cluster m_eos;  //TODO: make private?
    386 
    387     static long long CreateInstance(IMkvReader*, long long, Segment*&);
    388     ~Segment();
    389 
    390     //for big-bang loading (source filter)
    391     long Load();
    392 
    393     //for incremental loading (splitter)
    394     long long Unparsed() const;
    395     long long ParseHeaders();
    396     long ParseCluster(Cluster*&, long long& newpos) const;
    397     bool AddCluster(Cluster*, long long);
    398 
    399     Tracks* GetTracks() const;
    400     const SegmentInfo* const GetInfo() const;
    401     long long GetDuration() const;
    402 
    403     //NOTE: this turned out to be too inefficient.
    404     //long long Load(long long time_nanoseconds);
    405 
    406     Cluster* GetFirst();
    407     Cluster* GetLast();
    408     unsigned long GetCount() const;
    409 
    410     Cluster* GetNext(const Cluster*);
    411     Cluster* GetCluster(long long time_nanoseconds);
    412 
    413 private:
    414     long long m_pos;  //absolute file posn; what has been consumed so far
    415     SegmentInfo* m_pInfo;
    416     Tracks* m_pTracks;
    417     Cluster** m_clusters;
    418     size_t m_clusterCount;
    419 
    420     void ParseSeekHead(long long pos, long long size, size_t*);
    421     void ParseSeekEntry(long long pos, long long size, size_t*);
    422     void ParseSecondarySeekHead(long long off, size_t*);
    423 };
    424 
    425 
    426 }  //end namespace mkvparser
    427 
    428 #endif  //MKVPARSER_HPP
    429