Home | History | Annotate | Download | only in mkvparser
      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 
    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