Home | History | Annotate | Download | only in matroska
      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 };
     60 
     61 
     62 class Segment;
     63 class Track;
     64 class Cluster;
     65 
     66 class Block
     67 {
     68     Block(const Block&);
     69     Block& operator=(const Block&);
     70 
     71 public:
     72     const long long m_start;
     73     const long long m_size;
     74 
     75     Block(long long start, long long size, IMkvReader*);
     76 
     77     long long GetTrackNumber() const;
     78     long long GetTimeCode(Cluster*) const;  //absolute, but not scaled
     79     long long GetTime(Cluster*) const;      //absolute, and scaled (ns units)
     80     bool IsKey() const;
     81     void SetKey(bool);
     82 
     83     unsigned char Flags() const;
     84 
     85     long long GetOffset() const;
     86     long GetSize() const;
     87     long Read(IMkvReader*, unsigned char*) const;
     88 
     89 private:
     90     long long m_track;   //Track::Number()
     91     short m_timecode;  //relative to cluster
     92     unsigned char m_flags;
     93     long long m_frameOff;
     94     long m_frameSize;
     95 
     96 };
     97 
     98 
     99 class BlockEntry
    100 {
    101     BlockEntry(const BlockEntry&);
    102     BlockEntry& operator=(const BlockEntry&);
    103 
    104 public:
    105     virtual ~BlockEntry();
    106     virtual bool EOS() const = 0;
    107     virtual Cluster* GetCluster() const = 0;
    108     virtual size_t GetIndex() const = 0;
    109     virtual const Block* GetBlock() const = 0;
    110     virtual bool IsBFrame() const = 0;
    111 
    112 protected:
    113     BlockEntry();
    114 
    115 };
    116 
    117 
    118 class SimpleBlock : public BlockEntry
    119 {
    120     SimpleBlock(const SimpleBlock&);
    121     SimpleBlock& operator=(const SimpleBlock&);
    122 
    123 public:
    124     SimpleBlock(Cluster*, size_t, long long start, long long size);
    125 
    126     bool EOS() const;
    127     Cluster* GetCluster() const;
    128     size_t GetIndex() const;
    129     const Block* GetBlock() const;
    130     bool IsBFrame() const;
    131 
    132 protected:
    133     Cluster* const m_pCluster;
    134     const size_t m_index;
    135     Block m_block;
    136 
    137 };
    138 
    139 
    140 class BlockGroup : public BlockEntry
    141 {
    142     BlockGroup(const BlockGroup&);
    143     BlockGroup& operator=(const BlockGroup&);
    144 
    145 public:
    146     BlockGroup(Cluster*, size_t, long long, long long);
    147     ~BlockGroup();
    148 
    149     bool EOS() const;
    150     Cluster* GetCluster() const;
    151     size_t GetIndex() const;
    152     const Block* GetBlock() const;
    153     bool IsBFrame() const;
    154 
    155     short GetPrevTimeCode() const;  //relative to block's time
    156     short GetNextTimeCode() const;  //as above
    157 
    158 protected:
    159     Cluster* const m_pCluster;
    160     const size_t m_index;
    161 
    162 private:
    163     BlockGroup(Cluster*, size_t, unsigned long);
    164     void ParseBlock(long long start, long long size);
    165 
    166     short m_prevTimeCode;
    167     short m_nextTimeCode;
    168 
    169     //TODO: the Matroska spec says you can have multiple blocks within the
    170     //same block group, with blocks ranked by priority (the flag bits).
    171     //For now we just cache a single block.
    172 #if 0
    173     typedef std::deque<Block*> blocks_t;
    174     blocks_t m_blocks;  //In practice should contain only a single element.
    175 #else
    176     Block* m_pBlock;
    177 #endif
    178 
    179 };
    180 
    181 
    182 class Track
    183 {
    184     Track(const Track&);
    185     Track& operator=(const Track&);
    186 
    187 public:
    188     Segment* const m_pSegment;
    189     virtual ~Track();
    190 
    191     long long GetType() const;
    192     long long GetNumber() const;
    193     const char* GetNameAsUTF8() const;
    194     const char* GetCodecNameAsUTF8() const;
    195     const char* GetCodecId() const;
    196     const unsigned char* GetCodecPrivate(size_t&) const;
    197 
    198     const BlockEntry* GetEOS() const;
    199 
    200     struct Settings
    201     {
    202         long long start;
    203         long long size;
    204     };
    205 
    206     struct Info
    207     {
    208         long long type;
    209         long long number;
    210         long long uid;
    211         char* nameAsUTF8;
    212         char* codecId;
    213         unsigned char* codecPrivate;
    214         size_t codecPrivateSize;
    215         char* codecNameAsUTF8;
    216         Settings settings;
    217         Info();
    218         void Clear();
    219     };
    220 
    221     long GetFirst(const BlockEntry*&) const;
    222     long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
    223     virtual bool VetEntry(const BlockEntry*) const = 0;
    224 
    225 protected:
    226     Track(Segment*, const Info&);
    227     const Info m_info;
    228 
    229     class EOSBlock : public BlockEntry
    230     {
    231     public:
    232         EOSBlock();
    233 
    234         bool EOS() const;
    235         Cluster* GetCluster() const;
    236         size_t GetIndex() const;
    237         const Block* GetBlock() const;
    238         bool IsBFrame() const;
    239     };
    240 
    241     EOSBlock m_eos;
    242 
    243 };
    244 
    245 
    246 class VideoTrack : public Track
    247 {
    248     VideoTrack(const VideoTrack&);
    249     VideoTrack& operator=(const VideoTrack&);
    250 
    251 public:
    252     VideoTrack(Segment*, const Info&);
    253     long long GetWidth() const;
    254     long long GetHeight() const;
    255     double GetFrameRate() const;
    256 
    257     bool VetEntry(const BlockEntry*) const;
    258 
    259 private:
    260     long long m_width;
    261     long long m_height;
    262     double m_rate;
    263 
    264 };
    265 
    266 
    267 class AudioTrack : public Track
    268 {
    269     AudioTrack(const AudioTrack&);
    270     AudioTrack& operator=(const AudioTrack&);
    271 
    272 public:
    273     AudioTrack(Segment*, const Info&);
    274     double GetSamplingRate() const;
    275     long long GetChannels() const;
    276     long long GetBitDepth() const;
    277     bool VetEntry(const BlockEntry*) const;
    278 
    279 private:
    280     double m_rate;
    281     long long m_channels;
    282     long long m_bitDepth;
    283 };
    284 
    285 
    286 class Tracks
    287 {
    288     Tracks(const Tracks&);
    289     Tracks& operator=(const Tracks&);
    290 
    291 public:
    292     Segment* const m_pSegment;
    293     const long long m_start;
    294     const long long m_size;
    295 
    296     Tracks(Segment*, long long start, long long size);
    297     virtual ~Tracks();
    298 
    299     Track* GetTrackByNumber(unsigned long tn) const;
    300     Track* GetTrackByIndex(unsigned long idx) const;
    301 
    302 private:
    303     Track** m_trackEntries;
    304     Track** m_trackEntriesEnd;
    305 
    306     void ParseTrackEntry(long long, long long, Track*&);
    307 
    308 public:
    309     unsigned long GetTracksCount() const;
    310 };
    311 
    312 
    313 class SegmentInfo
    314 {
    315     SegmentInfo(const SegmentInfo&);
    316     SegmentInfo& operator=(const SegmentInfo&);
    317 
    318 public:
    319     Segment* const m_pSegment;
    320     const long long m_start;
    321     const long long m_size;
    322 
    323     SegmentInfo(Segment*, long long start, long long size);
    324     ~SegmentInfo();
    325     long long GetTimeCodeScale() const;
    326     long long GetDuration() const;  //scaled
    327     const char* GetMuxingAppAsUTF8() const;
    328     const char* GetWritingAppAsUTF8() const;
    329     const char* GetTitleAsUTF8() const;
    330 
    331 private:
    332     long long m_timecodeScale;
    333     double m_duration;
    334     char* m_pMuxingAppAsUTF8;
    335     char* m_pWritingAppAsUTF8;
    336     char* m_pTitleAsUTF8;
    337 };
    338 
    339 class Cues;
    340 class CuePoint
    341 {
    342     friend class Cues;
    343 
    344     CuePoint(size_t, long long);
    345     ~CuePoint();
    346 
    347     CuePoint(const CuePoint&);
    348     CuePoint& operator=(const CuePoint&);
    349 
    350 public:
    351     void Load(IMkvReader*);
    352 
    353     long long GetTimeCode() const;      //absolute but unscaled
    354     long long GetTime(Segment*) const;  //absolute and scaled (ns units)
    355 
    356     struct TrackPosition
    357     {
    358         long long m_track;
    359         long long m_pos;  //of cluster
    360         long long m_block;
    361         //codec_state  //defaults to 0
    362         //reference = clusters containing req'd referenced blocks
    363         //  reftime = timecode of the referenced block
    364 
    365         void Parse(IMkvReader*, long long, long long);
    366     };
    367 
    368     const TrackPosition* Find(const Track*) const;
    369 
    370 private:
    371     const size_t m_index;
    372     long long m_timecode;
    373     TrackPosition* m_track_positions;
    374     size_t m_track_positions_count;
    375 
    376 };
    377 
    378 
    379 class Cues
    380 {
    381     friend class Segment;
    382 
    383     Cues(Segment*, long long start, long long size);
    384     ~Cues();
    385 
    386     Cues(const Cues&);
    387     Cues& operator=(const Cues&);
    388 
    389 public:
    390     Segment* const m_pSegment;
    391     const long long m_start;
    392     const long long m_size;
    393 
    394     bool Find(  //lower bound of time_ns
    395         long long time_ns,
    396         const Track*,
    397         const CuePoint*&,
    398         const CuePoint::TrackPosition*&) const;
    399 
    400 #if 0
    401     bool FindNext(  //upper_bound of time_ns
    402         long long time_ns,
    403         const Track*,
    404         const CuePoint*&,
    405         const CuePoint::TrackPosition*&) const;
    406 #endif
    407 
    408     const CuePoint* GetFirst() const;
    409     const CuePoint* GetLast() const;
    410 
    411     const CuePoint* GetNext(const CuePoint*) const;
    412 
    413     const BlockEntry* GetBlock(
    414                         const CuePoint*,
    415                         const CuePoint::TrackPosition*) const;
    416 
    417 private:
    418     void Init() const;
    419     bool LoadCuePoint() const;
    420     void PreloadCuePoint(size_t&, long long) const;
    421 
    422     mutable CuePoint** m_cue_points;
    423     mutable size_t m_count;
    424     mutable size_t m_preload_count;
    425     mutable long long m_pos;
    426 
    427 };
    428 
    429 
    430 class Cluster
    431 {
    432     Cluster(const Cluster&);
    433     Cluster& operator=(const Cluster&);
    434 
    435 public:
    436     Segment* const m_pSegment;
    437 
    438 public:
    439     static Cluster* Parse(Segment*, long, long long off);
    440 
    441     Cluster();  //EndOfStream
    442     ~Cluster();
    443 
    444     bool EOS() const;
    445 
    446     long long GetTimeCode();   //absolute, but not scaled
    447     long long GetTime();       //absolute, and scaled (nanosecond units)
    448     long long GetFirstTime();  //time (ns) of first (earliest) block
    449     long long GetLastTime();   //time (ns) of last (latest) block
    450 
    451     const BlockEntry* GetFirst();
    452     const BlockEntry* GetLast();
    453     const BlockEntry* GetNext(const BlockEntry*) const;
    454     const BlockEntry* GetEntry(const Track*);
    455     const BlockEntry* GetEntry(
    456         const CuePoint&,
    457         const CuePoint::TrackPosition&);
    458     const BlockEntry* GetMaxKey(const VideoTrack*);
    459 
    460 protected:
    461     Cluster(Segment*, long, long long off);
    462 
    463 public:
    464     //TODO: these should all be private, with public selector functions
    465     long m_index;
    466     long long m_pos;
    467     long long m_size;
    468 
    469 private:
    470     long long m_timecode;
    471     BlockEntry** m_entries;
    472     size_t m_entriesCount;
    473 
    474     void Load();
    475     void LoadBlockEntries();
    476     void ParseBlockGroup(long long, long long, size_t);
    477     void ParseSimpleBlock(long long, long long, size_t);
    478 
    479 };
    480 
    481 
    482 class Segment
    483 {
    484     friend class Cues;
    485 
    486     Segment(const Segment&);
    487     Segment& operator=(const Segment&);
    488 
    489 private:
    490     Segment(IMkvReader*, long long pos, long long size);
    491 
    492 public:
    493     IMkvReader* const m_pReader;
    494     const long long m_start;  //posn of segment payload
    495     const long long m_size;   //size of segment payload
    496     Cluster m_eos;  //TODO: make private?
    497 
    498     static long long CreateInstance(IMkvReader*, long long, Segment*&);
    499     ~Segment();
    500 
    501     long Load();  //loads headers and all clusters
    502 
    503     //for incremental loading (splitter)
    504     long long Unparsed() const;
    505     long long ParseHeaders();  //stops when first cluster is found
    506     long LoadCluster();        //loads one cluster
    507 
    508 #if 0
    509     //This pair parses one cluster, but only changes the state of the
    510     //segment object when the cluster is actually added to the index.
    511     long ParseCluster(Cluster*&, long long& newpos) const;
    512     bool AddCluster(Cluster*, long long);
    513 #endif
    514 
    515     Tracks* GetTracks() const;
    516     const SegmentInfo* GetInfo() const;
    517     const Cues* GetCues() const;
    518 
    519     long long GetDuration() const;
    520 
    521     unsigned long GetCount() const;
    522     Cluster* GetFirst();
    523     Cluster* GetLast();
    524     Cluster* GetNext(const Cluster*);
    525 
    526     Cluster* FindCluster(long long time_nanoseconds);
    527     const BlockEntry* Seek(long long time_nanoseconds, const Track*);
    528 
    529 private:
    530 
    531     long long m_pos;  //absolute file posn; what has been consumed so far
    532     SegmentInfo* m_pInfo;
    533     Tracks* m_pTracks;
    534     Cues* m_pCues;
    535     Cluster** m_clusters;
    536     long m_clusterCount;         //number of entries for which m_index >= 0
    537     long m_clusterPreloadCount;  //number of entries for which m_index < 0
    538     long m_clusterSize;          //array size
    539 
    540     void AppendCluster(Cluster*);
    541     void PreloadCluster(Cluster*, ptrdiff_t);
    542 
    543     void ParseSeekHead(long long pos, long long size);
    544     void ParseSeekEntry(long long pos, long long size);
    545     void ParseCues(long long);
    546 
    547     const BlockEntry* GetBlock(
    548         const CuePoint&,
    549         const CuePoint::TrackPosition&);
    550 
    551 };
    552 
    553 
    554 }  //end namespace mkvparser
    555 
    556 #endif  //MKVPARSER_HPP
    557