|  | // Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style license | 
|  | // that can be found in the LICENSE file in the root of the source | 
|  | // tree. An additional intellectual property rights grant can be found | 
|  | // in the file PATENTS.  All contributing project authors may | 
|  | // be found in the AUTHORS file in the root of the source tree. | 
|  | #ifndef MKVPARSER_MKVPARSER_H_ | 
|  | #define MKVPARSER_MKVPARSER_H_ | 
|  |  | 
|  | #include <cstddef> | 
|  |  | 
|  | namespace mkvparser { | 
|  |  | 
|  | const int E_PARSE_FAILED = -1; | 
|  | const int E_FILE_FORMAT_INVALID = -2; | 
|  | const int E_BUFFER_NOT_FULL = -3; | 
|  |  | 
|  | class IMkvReader { | 
|  | public: | 
|  | virtual int Read(long long pos, long len, unsigned char* buf) = 0; | 
|  | virtual int Length(long long* total, long long* available) = 0; | 
|  |  | 
|  | protected: | 
|  | virtual ~IMkvReader() {} | 
|  | }; | 
|  |  | 
|  | template <typename Type> | 
|  | Type* SafeArrayAlloc(unsigned long long num_elements, | 
|  | unsigned long long element_size); | 
|  | long long GetUIntLength(IMkvReader*, long long, long&); | 
|  | long long ReadUInt(IMkvReader*, long long, long&); | 
|  | long long ReadID(IMkvReader* pReader, long long pos, long& len); | 
|  | long long UnserializeUInt(IMkvReader*, long long pos, long long size); | 
|  |  | 
|  | long UnserializeFloat(IMkvReader*, long long pos, long long size, double&); | 
|  | long UnserializeInt(IMkvReader*, long long pos, long long size, | 
|  | long long& result); | 
|  |  | 
|  | long UnserializeString(IMkvReader*, long long pos, long long size, char*& str); | 
|  |  | 
|  | long ParseElementHeader(IMkvReader* pReader, | 
|  | long long& pos,  // consume id and size fields | 
|  | long long stop,  // if you know size of element's parent | 
|  | long long& id, long long& size); | 
|  |  | 
|  | bool Match(IMkvReader*, long long&, unsigned long, long long&); | 
|  | bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&); | 
|  |  | 
|  | void GetVersion(int& major, int& minor, int& build, int& revision); | 
|  |  | 
|  | struct EBMLHeader { | 
|  | EBMLHeader(); | 
|  | ~EBMLHeader(); | 
|  | long long m_version; | 
|  | long long m_readVersion; | 
|  | long long m_maxIdLength; | 
|  | long long m_maxSizeLength; | 
|  | char* m_docType; | 
|  | long long m_docTypeVersion; | 
|  | long long m_docTypeReadVersion; | 
|  |  | 
|  | long long Parse(IMkvReader*, long long&); | 
|  | void Init(); | 
|  | }; | 
|  |  | 
|  | class Segment; | 
|  | class Track; | 
|  | class Cluster; | 
|  |  | 
|  | class Block { | 
|  | Block(const Block&); | 
|  | Block& operator=(const Block&); | 
|  |  | 
|  | public: | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  |  | 
|  | Block(long long start, long long size, long long discard_padding); | 
|  | ~Block(); | 
|  |  | 
|  | long Parse(const Cluster*); | 
|  |  | 
|  | long long GetTrackNumber() const; | 
|  | long long GetTimeCode(const Cluster*) const;  // absolute, but not scaled | 
|  | long long GetTime(const Cluster*) const;  // absolute, and scaled (ns) | 
|  | bool IsKey() const; | 
|  | void SetKey(bool); | 
|  | bool IsInvisible() const; | 
|  |  | 
|  | enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml }; | 
|  | Lacing GetLacing() const; | 
|  |  | 
|  | int GetFrameCount() const;  // to index frames: [0, count) | 
|  |  | 
|  | struct Frame { | 
|  | long long pos;  // absolute offset | 
|  | long len; | 
|  |  | 
|  | long Read(IMkvReader*, unsigned char*) const; | 
|  | }; | 
|  |  | 
|  | const Frame& GetFrame(int frame_index) const; | 
|  |  | 
|  | long long GetDiscardPadding() const; | 
|  |  | 
|  | private: | 
|  | long long m_track;  // Track::Number() | 
|  | short m_timecode;  // relative to cluster | 
|  | unsigned char m_flags; | 
|  |  | 
|  | Frame* m_frames; | 
|  | int m_frame_count; | 
|  |  | 
|  | protected: | 
|  | const long long m_discard_padding; | 
|  | }; | 
|  |  | 
|  | class BlockEntry { | 
|  | BlockEntry(const BlockEntry&); | 
|  | BlockEntry& operator=(const BlockEntry&); | 
|  |  | 
|  | protected: | 
|  | BlockEntry(Cluster*, long index); | 
|  |  | 
|  | public: | 
|  | virtual ~BlockEntry(); | 
|  |  | 
|  | bool EOS() const { return (GetKind() == kBlockEOS); } | 
|  | const Cluster* GetCluster() const; | 
|  | long GetIndex() const; | 
|  | virtual const Block* GetBlock() const = 0; | 
|  |  | 
|  | enum Kind { kBlockEOS, kBlockSimple, kBlockGroup }; | 
|  | virtual Kind GetKind() const = 0; | 
|  |  | 
|  | protected: | 
|  | Cluster* const m_pCluster; | 
|  | const long m_index; | 
|  | }; | 
|  |  | 
|  | class SimpleBlock : public BlockEntry { | 
|  | SimpleBlock(const SimpleBlock&); | 
|  | SimpleBlock& operator=(const SimpleBlock&); | 
|  |  | 
|  | public: | 
|  | SimpleBlock(Cluster*, long index, long long start, long long size); | 
|  | long Parse(); | 
|  |  | 
|  | Kind GetKind() const; | 
|  | const Block* GetBlock() const; | 
|  |  | 
|  | protected: | 
|  | Block m_block; | 
|  | }; | 
|  |  | 
|  | class BlockGroup : public BlockEntry { | 
|  | BlockGroup(const BlockGroup&); | 
|  | BlockGroup& operator=(const BlockGroup&); | 
|  |  | 
|  | public: | 
|  | BlockGroup(Cluster*, long index, | 
|  | long long block_start,  // absolute pos of block's payload | 
|  | long long block_size,  // size of block's payload | 
|  | long long prev, long long next, long long duration, | 
|  | long long discard_padding); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | Kind GetKind() const; | 
|  | const Block* GetBlock() const; | 
|  |  | 
|  | long long GetPrevTimeCode() const;  // relative to block's time | 
|  | long long GetNextTimeCode() const;  // as above | 
|  | long long GetDurationTimeCode() const; | 
|  |  | 
|  | private: | 
|  | Block m_block; | 
|  | const long long m_prev; | 
|  | const long long m_next; | 
|  | const long long m_duration; | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////// | 
|  | // ContentEncoding element | 
|  | // Elements used to describe if the track data has been encrypted or | 
|  | // compressed with zlib or header stripping. | 
|  | class ContentEncoding { | 
|  | public: | 
|  | enum { kCTR = 1 }; | 
|  |  | 
|  | ContentEncoding(); | 
|  | ~ContentEncoding(); | 
|  |  | 
|  | // ContentCompression element names | 
|  | struct ContentCompression { | 
|  | ContentCompression(); | 
|  | ~ContentCompression(); | 
|  |  | 
|  | unsigned long long algo; | 
|  | unsigned char* settings; | 
|  | long long settings_len; | 
|  | }; | 
|  |  | 
|  | // ContentEncAESSettings element names | 
|  | struct ContentEncAESSettings { | 
|  | ContentEncAESSettings() : cipher_mode(kCTR) {} | 
|  | ~ContentEncAESSettings() {} | 
|  |  | 
|  | unsigned long long cipher_mode; | 
|  | }; | 
|  |  | 
|  | // ContentEncryption element names | 
|  | struct ContentEncryption { | 
|  | ContentEncryption(); | 
|  | ~ContentEncryption(); | 
|  |  | 
|  | unsigned long long algo; | 
|  | unsigned char* key_id; | 
|  | long long key_id_len; | 
|  | unsigned char* signature; | 
|  | long long signature_len; | 
|  | unsigned char* sig_key_id; | 
|  | long long sig_key_id_len; | 
|  | unsigned long long sig_algo; | 
|  | unsigned long long sig_hash_algo; | 
|  |  | 
|  | ContentEncAESSettings aes_settings; | 
|  | }; | 
|  |  | 
|  | // Returns ContentCompression represented by |idx|. Returns NULL if |idx| | 
|  | // is out of bounds. | 
|  | const ContentCompression* GetCompressionByIndex(unsigned long idx) const; | 
|  |  | 
|  | // Returns number of ContentCompression elements in this ContentEncoding | 
|  | // element. | 
|  | unsigned long GetCompressionCount() const; | 
|  |  | 
|  | // Parses the ContentCompression element from |pReader|. |start| is the | 
|  | // starting offset of the ContentCompression payload. |size| is the size in | 
|  | // bytes of the ContentCompression payload. |compression| is where the parsed | 
|  | // values will be stored. | 
|  | long ParseCompressionEntry(long long start, long long size, | 
|  | IMkvReader* pReader, | 
|  | ContentCompression* compression); | 
|  |  | 
|  | // Returns ContentEncryption represented by |idx|. Returns NULL if |idx| | 
|  | // is out of bounds. | 
|  | const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const; | 
|  |  | 
|  | // Returns number of ContentEncryption elements in this ContentEncoding | 
|  | // element. | 
|  | unsigned long GetEncryptionCount() const; | 
|  |  | 
|  | // Parses the ContentEncAESSettings element from |pReader|. |start| is the | 
|  | // starting offset of the ContentEncAESSettings payload. |size| is the | 
|  | // size in bytes of the ContentEncAESSettings payload. |encryption| is | 
|  | // where the parsed values will be stored. | 
|  | long ParseContentEncAESSettingsEntry(long long start, long long size, | 
|  | IMkvReader* pReader, | 
|  | ContentEncAESSettings* aes); | 
|  |  | 
|  | // Parses the ContentEncoding element from |pReader|. |start| is the | 
|  | // starting offset of the ContentEncoding payload. |size| is the size in | 
|  | // bytes of the ContentEncoding payload. Returns true on success. | 
|  | long ParseContentEncodingEntry(long long start, long long size, | 
|  | IMkvReader* pReader); | 
|  |  | 
|  | // Parses the ContentEncryption element from |pReader|. |start| is the | 
|  | // starting offset of the ContentEncryption payload. |size| is the size in | 
|  | // bytes of the ContentEncryption payload. |encryption| is where the parsed | 
|  | // values will be stored. | 
|  | long ParseEncryptionEntry(long long start, long long size, | 
|  | IMkvReader* pReader, ContentEncryption* encryption); | 
|  |  | 
|  | unsigned long long encoding_order() const { return encoding_order_; } | 
|  | unsigned long long encoding_scope() const { return encoding_scope_; } | 
|  | unsigned long long encoding_type() const { return encoding_type_; } | 
|  |  | 
|  | private: | 
|  | // Member variables for list of ContentCompression elements. | 
|  | ContentCompression** compression_entries_; | 
|  | ContentCompression** compression_entries_end_; | 
|  |  | 
|  | // Member variables for list of ContentEncryption elements. | 
|  | ContentEncryption** encryption_entries_; | 
|  | ContentEncryption** encryption_entries_end_; | 
|  |  | 
|  | // ContentEncoding element names | 
|  | unsigned long long encoding_order_; | 
|  | unsigned long long encoding_scope_; | 
|  | unsigned long long encoding_type_; | 
|  |  | 
|  | // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding); | 
|  | ContentEncoding(const ContentEncoding&); | 
|  | ContentEncoding& operator=(const ContentEncoding&); | 
|  | }; | 
|  |  | 
|  | class Track { | 
|  | Track(const Track&); | 
|  | Track& operator=(const Track&); | 
|  |  | 
|  | public: | 
|  | class Info; | 
|  | static long Create(Segment*, const Info&, long long element_start, | 
|  | long long element_size, Track*&); | 
|  |  | 
|  | enum Type { kVideo = 1, kAudio = 2, kSubtitle = 0x11, kMetadata = 0x21 }; | 
|  |  | 
|  | Segment* const m_pSegment; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  | virtual ~Track(); | 
|  |  | 
|  | long GetType() const; | 
|  | long GetNumber() const; | 
|  | unsigned long long GetUid() const; | 
|  | const char* GetNameAsUTF8() const; | 
|  | const char* GetLanguage() const; | 
|  | const char* GetCodecNameAsUTF8() const; | 
|  | const char* GetCodecId() const; | 
|  | const unsigned char* GetCodecPrivate(size_t&) const; | 
|  | bool GetLacing() const; | 
|  | unsigned long long GetDefaultDuration() const; | 
|  | unsigned long long GetCodecDelay() const; | 
|  | unsigned long long GetSeekPreRoll() const; | 
|  |  | 
|  | const BlockEntry* GetEOS() const; | 
|  |  | 
|  | struct Settings { | 
|  | long long start; | 
|  | long long size; | 
|  | }; | 
|  |  | 
|  | class Info { | 
|  | public: | 
|  | Info(); | 
|  | ~Info(); | 
|  | int Copy(Info&) const; | 
|  | void Clear(); | 
|  | long type; | 
|  | long number; | 
|  | unsigned long long uid; | 
|  | unsigned long long defaultDuration; | 
|  | unsigned long long codecDelay; | 
|  | unsigned long long seekPreRoll; | 
|  | char* nameAsUTF8; | 
|  | char* language; | 
|  | char* codecId; | 
|  | char* codecNameAsUTF8; | 
|  | unsigned char* codecPrivate; | 
|  | size_t codecPrivateSize; | 
|  | bool lacing; | 
|  | Settings settings; | 
|  |  | 
|  | private: | 
|  | Info(const Info&); | 
|  | Info& operator=(const Info&); | 
|  | int CopyStr(char* Info::*str, Info&) const; | 
|  | }; | 
|  |  | 
|  | long GetFirst(const BlockEntry*&) const; | 
|  | long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; | 
|  | virtual bool VetEntry(const BlockEntry*) const; | 
|  | virtual long Seek(long long time_ns, const BlockEntry*&) const; | 
|  |  | 
|  | const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const; | 
|  | unsigned long GetContentEncodingCount() const; | 
|  |  | 
|  | long ParseContentEncodingsEntry(long long start, long long size); | 
|  |  | 
|  | protected: | 
|  | Track(Segment*, long long element_start, long long element_size); | 
|  |  | 
|  | Info m_info; | 
|  |  | 
|  | class EOSBlock : public BlockEntry { | 
|  | public: | 
|  | EOSBlock(); | 
|  |  | 
|  | Kind GetKind() const; | 
|  | const Block* GetBlock() const; | 
|  | }; | 
|  |  | 
|  | EOSBlock m_eos; | 
|  |  | 
|  | private: | 
|  | ContentEncoding** content_encoding_entries_; | 
|  | ContentEncoding** content_encoding_entries_end_; | 
|  | }; | 
|  |  | 
|  | struct PrimaryChromaticity { | 
|  | PrimaryChromaticity() : x(0), y(0) {} | 
|  | ~PrimaryChromaticity() {} | 
|  | static bool Parse(IMkvReader* reader, long long read_pos, | 
|  | long long value_size, bool is_x, | 
|  | PrimaryChromaticity** chromaticity); | 
|  | float x; | 
|  | float y; | 
|  | }; | 
|  |  | 
|  | struct MasteringMetadata { | 
|  | static const float kValueNotPresent; | 
|  |  | 
|  | MasteringMetadata() | 
|  | : r(NULL), | 
|  | g(NULL), | 
|  | b(NULL), | 
|  | white_point(NULL), | 
|  | luminance_max(kValueNotPresent), | 
|  | luminance_min(kValueNotPresent) {} | 
|  | ~MasteringMetadata() { | 
|  | delete r; | 
|  | delete g; | 
|  | delete b; | 
|  | delete white_point; | 
|  | } | 
|  |  | 
|  | static bool Parse(IMkvReader* reader, long long element_start, | 
|  | long long element_size, | 
|  | MasteringMetadata** mastering_metadata); | 
|  |  | 
|  | PrimaryChromaticity* r; | 
|  | PrimaryChromaticity* g; | 
|  | PrimaryChromaticity* b; | 
|  | PrimaryChromaticity* white_point; | 
|  | float luminance_max; | 
|  | float luminance_min; | 
|  | }; | 
|  |  | 
|  | struct Colour { | 
|  | static const long long kValueNotPresent; | 
|  |  | 
|  | // Unless otherwise noted all values assigned upon construction are the | 
|  | // equivalent of unspecified/default. | 
|  | Colour() | 
|  | : matrix_coefficients(kValueNotPresent), | 
|  | bits_per_channel(kValueNotPresent), | 
|  | chroma_subsampling_horz(kValueNotPresent), | 
|  | chroma_subsampling_vert(kValueNotPresent), | 
|  | cb_subsampling_horz(kValueNotPresent), | 
|  | cb_subsampling_vert(kValueNotPresent), | 
|  | chroma_siting_horz(kValueNotPresent), | 
|  | chroma_siting_vert(kValueNotPresent), | 
|  | range(kValueNotPresent), | 
|  | transfer_characteristics(kValueNotPresent), | 
|  | primaries(kValueNotPresent), | 
|  | max_cll(kValueNotPresent), | 
|  | max_fall(kValueNotPresent), | 
|  | mastering_metadata(NULL) {} | 
|  | ~Colour() { | 
|  | delete mastering_metadata; | 
|  | mastering_metadata = NULL; | 
|  | } | 
|  |  | 
|  | static bool Parse(IMkvReader* reader, long long element_start, | 
|  | long long element_size, Colour** colour); | 
|  |  | 
|  | long long matrix_coefficients; | 
|  | long long bits_per_channel; | 
|  | long long chroma_subsampling_horz; | 
|  | long long chroma_subsampling_vert; | 
|  | long long cb_subsampling_horz; | 
|  | long long cb_subsampling_vert; | 
|  | long long chroma_siting_horz; | 
|  | long long chroma_siting_vert; | 
|  | long long range; | 
|  | long long transfer_characteristics; | 
|  | long long primaries; | 
|  | long long max_cll; | 
|  | long long max_fall; | 
|  |  | 
|  | MasteringMetadata* mastering_metadata; | 
|  | }; | 
|  |  | 
|  | struct Projection { | 
|  | enum ProjectionType { | 
|  | kTypeNotPresent = -1, | 
|  | kRectangular = 0, | 
|  | kEquirectangular = 1, | 
|  | kCubeMap = 2, | 
|  | kMesh = 3, | 
|  | }; | 
|  | static const float kValueNotPresent; | 
|  | Projection() | 
|  | : type(kTypeNotPresent), | 
|  | private_data(NULL), | 
|  | private_data_length(0), | 
|  | pose_yaw(kValueNotPresent), | 
|  | pose_pitch(kValueNotPresent), | 
|  | pose_roll(kValueNotPresent) {} | 
|  | ~Projection() { delete[] private_data; } | 
|  | static bool Parse(IMkvReader* reader, long long element_start, | 
|  | long long element_size, Projection** projection); | 
|  |  | 
|  | ProjectionType type; | 
|  | unsigned char* private_data; | 
|  | size_t private_data_length; | 
|  | float pose_yaw; | 
|  | float pose_pitch; | 
|  | float pose_roll; | 
|  | }; | 
|  |  | 
|  | class VideoTrack : public Track { | 
|  | VideoTrack(const VideoTrack&); | 
|  | VideoTrack& operator=(const VideoTrack&); | 
|  |  | 
|  | VideoTrack(Segment*, long long element_start, long long element_size); | 
|  |  | 
|  | public: | 
|  | virtual ~VideoTrack(); | 
|  | static long Parse(Segment*, const Info&, long long element_start, | 
|  | long long element_size, VideoTrack*&); | 
|  |  | 
|  | long long GetWidth() const; | 
|  | long long GetHeight() const; | 
|  | long long GetDisplayWidth() const; | 
|  | long long GetDisplayHeight() const; | 
|  | long long GetDisplayUnit() const; | 
|  | long long GetStereoMode() const; | 
|  | double GetFrameRate() const; | 
|  |  | 
|  | bool VetEntry(const BlockEntry*) const; | 
|  | long Seek(long long time_ns, const BlockEntry*&) const; | 
|  |  | 
|  | Colour* GetColour() const; | 
|  |  | 
|  | Projection* GetProjection() const; | 
|  |  | 
|  | const char* GetColourSpace() const { return m_colour_space; } | 
|  |  | 
|  | private: | 
|  | long long m_width; | 
|  | long long m_height; | 
|  | long long m_display_width; | 
|  | long long m_display_height; | 
|  | long long m_display_unit; | 
|  | long long m_stereo_mode; | 
|  | char* m_colour_space; | 
|  | double m_rate; | 
|  |  | 
|  | Colour* m_colour; | 
|  | Projection* m_projection; | 
|  | }; | 
|  |  | 
|  | class AudioTrack : public Track { | 
|  | AudioTrack(const AudioTrack&); | 
|  | AudioTrack& operator=(const AudioTrack&); | 
|  |  | 
|  | AudioTrack(Segment*, long long element_start, long long element_size); | 
|  |  | 
|  | public: | 
|  | static long Parse(Segment*, const Info&, long long element_start, | 
|  | long long element_size, AudioTrack*&); | 
|  |  | 
|  | double GetSamplingRate() const; | 
|  | long long GetChannels() const; | 
|  | long long GetBitDepth() const; | 
|  |  | 
|  | private: | 
|  | double m_rate; | 
|  | long long m_channels; | 
|  | long long m_bitDepth; | 
|  | }; | 
|  |  | 
|  | class Tracks { | 
|  | Tracks(const Tracks&); | 
|  | Tracks& operator=(const Tracks&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | Tracks(Segment*, long long start, long long size, long long element_start, | 
|  | long long element_size); | 
|  |  | 
|  | ~Tracks(); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | unsigned long GetTracksCount() const; | 
|  |  | 
|  | const Track* GetTrackByNumber(long tn) const; | 
|  | const Track* GetTrackByIndex(unsigned long idx) const; | 
|  |  | 
|  | private: | 
|  | Track** m_trackEntries; | 
|  | Track** m_trackEntriesEnd; | 
|  |  | 
|  | long ParseTrackEntry(long long payload_start, long long payload_size, | 
|  | long long element_start, long long element_size, | 
|  | Track*&) const; | 
|  | }; | 
|  |  | 
|  | class Chapters { | 
|  | Chapters(const Chapters&); | 
|  | Chapters& operator=(const Chapters&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | Chapters(Segment*, long long payload_start, long long payload_size, | 
|  | long long element_start, long long element_size); | 
|  |  | 
|  | ~Chapters(); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | class Atom; | 
|  | class Edition; | 
|  |  | 
|  | class Display { | 
|  | friend class Atom; | 
|  | Display(); | 
|  | Display(const Display&); | 
|  | ~Display(); | 
|  | Display& operator=(const Display&); | 
|  |  | 
|  | public: | 
|  | const char* GetString() const; | 
|  | const char* GetLanguage() const; | 
|  | const char* GetCountry() const; | 
|  |  | 
|  | private: | 
|  | void Init(); | 
|  | void ShallowCopy(Display&) const; | 
|  | void Clear(); | 
|  | long Parse(IMkvReader*, long long pos, long long size); | 
|  |  | 
|  | char* m_string; | 
|  | char* m_language; | 
|  | char* m_country; | 
|  | }; | 
|  |  | 
|  | class Atom { | 
|  | friend class Edition; | 
|  | Atom(); | 
|  | Atom(const Atom&); | 
|  | ~Atom(); | 
|  | Atom& operator=(const Atom&); | 
|  |  | 
|  | public: | 
|  | unsigned long long GetUID() const; | 
|  | const char* GetStringUID() const; | 
|  |  | 
|  | long long GetStartTimecode() const; | 
|  | long long GetStopTimecode() const; | 
|  |  | 
|  | long long GetStartTime(const Chapters*) const; | 
|  | long long GetStopTime(const Chapters*) const; | 
|  |  | 
|  | int GetDisplayCount() const; | 
|  | const Display* GetDisplay(int index) const; | 
|  |  | 
|  | private: | 
|  | void Init(); | 
|  | void ShallowCopy(Atom&) const; | 
|  | void Clear(); | 
|  | long Parse(IMkvReader*, long long pos, long long size); | 
|  | static long long GetTime(const Chapters*, long long timecode); | 
|  |  | 
|  | long ParseDisplay(IMkvReader*, long long pos, long long size); | 
|  | bool ExpandDisplaysArray(); | 
|  |  | 
|  | char* m_string_uid; | 
|  | unsigned long long m_uid; | 
|  | long long m_start_timecode; | 
|  | long long m_stop_timecode; | 
|  |  | 
|  | Display* m_displays; | 
|  | int m_displays_size; | 
|  | int m_displays_count; | 
|  | }; | 
|  |  | 
|  | class Edition { | 
|  | friend class Chapters; | 
|  | Edition(); | 
|  | Edition(const Edition&); | 
|  | ~Edition(); | 
|  | Edition& operator=(const Edition&); | 
|  |  | 
|  | public: | 
|  | int GetAtomCount() const; | 
|  | const Atom* GetAtom(int index) const; | 
|  |  | 
|  | private: | 
|  | void Init(); | 
|  | void ShallowCopy(Edition&) const; | 
|  | void Clear(); | 
|  | long Parse(IMkvReader*, long long pos, long long size); | 
|  |  | 
|  | long ParseAtom(IMkvReader*, long long pos, long long size); | 
|  | bool ExpandAtomsArray(); | 
|  |  | 
|  | Atom* m_atoms; | 
|  | int m_atoms_size; | 
|  | int m_atoms_count; | 
|  | }; | 
|  |  | 
|  | int GetEditionCount() const; | 
|  | const Edition* GetEdition(int index) const; | 
|  |  | 
|  | private: | 
|  | long ParseEdition(long long pos, long long size); | 
|  | bool ExpandEditionsArray(); | 
|  |  | 
|  | Edition* m_editions; | 
|  | int m_editions_size; | 
|  | int m_editions_count; | 
|  | }; | 
|  |  | 
|  | class Tags { | 
|  | Tags(const Tags&); | 
|  | Tags& operator=(const Tags&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | Tags(Segment*, long long payload_start, long long payload_size, | 
|  | long long element_start, long long element_size); | 
|  |  | 
|  | ~Tags(); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | class Tag; | 
|  | class SimpleTag; | 
|  |  | 
|  | class SimpleTag { | 
|  | friend class Tag; | 
|  | SimpleTag(); | 
|  | SimpleTag(const SimpleTag&); | 
|  | ~SimpleTag(); | 
|  | SimpleTag& operator=(const SimpleTag&); | 
|  |  | 
|  | public: | 
|  | const char* GetTagName() const; | 
|  | const char* GetTagString() const; | 
|  |  | 
|  | private: | 
|  | void Init(); | 
|  | void ShallowCopy(SimpleTag&) const; | 
|  | void Clear(); | 
|  | long Parse(IMkvReader*, long long pos, long long size); | 
|  |  | 
|  | char* m_tag_name; | 
|  | char* m_tag_string; | 
|  | }; | 
|  |  | 
|  | class Tag { | 
|  | friend class Tags; | 
|  | Tag(); | 
|  | Tag(const Tag&); | 
|  | ~Tag(); | 
|  | Tag& operator=(const Tag&); | 
|  |  | 
|  | public: | 
|  | int GetSimpleTagCount() const; | 
|  | const SimpleTag* GetSimpleTag(int index) const; | 
|  |  | 
|  | private: | 
|  | void Init(); | 
|  | void ShallowCopy(Tag&) const; | 
|  | void Clear(); | 
|  | long Parse(IMkvReader*, long long pos, long long size); | 
|  |  | 
|  | long ParseSimpleTag(IMkvReader*, long long pos, long long size); | 
|  | bool ExpandSimpleTagsArray(); | 
|  |  | 
|  | SimpleTag* m_simple_tags; | 
|  | int m_simple_tags_size; | 
|  | int m_simple_tags_count; | 
|  | }; | 
|  |  | 
|  | int GetTagCount() const; | 
|  | const Tag* GetTag(int index) const; | 
|  |  | 
|  | private: | 
|  | long ParseTag(long long pos, long long size); | 
|  | bool ExpandTagsArray(); | 
|  |  | 
|  | Tag* m_tags; | 
|  | int m_tags_size; | 
|  | int m_tags_count; | 
|  | }; | 
|  |  | 
|  | class SegmentInfo { | 
|  | SegmentInfo(const SegmentInfo&); | 
|  | SegmentInfo& operator=(const SegmentInfo&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | SegmentInfo(Segment*, long long start, long long size, | 
|  | long long element_start, long long element_size); | 
|  |  | 
|  | ~SegmentInfo(); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | long long GetTimeCodeScale() const; | 
|  | long long GetDuration() const;  // scaled | 
|  | const char* GetMuxingAppAsUTF8() const; | 
|  | const char* GetWritingAppAsUTF8() const; | 
|  | const char* GetTitleAsUTF8() const; | 
|  |  | 
|  | private: | 
|  | long long m_timecodeScale; | 
|  | double m_duration; | 
|  | char* m_pMuxingAppAsUTF8; | 
|  | char* m_pWritingAppAsUTF8; | 
|  | char* m_pTitleAsUTF8; | 
|  | }; | 
|  |  | 
|  | class SeekHead { | 
|  | SeekHead(const SeekHead&); | 
|  | SeekHead& operator=(const SeekHead&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | SeekHead(Segment*, long long start, long long size, long long element_start, | 
|  | long long element_size); | 
|  |  | 
|  | ~SeekHead(); | 
|  |  | 
|  | long Parse(); | 
|  |  | 
|  | struct Entry { | 
|  | Entry(); | 
|  |  | 
|  | // the SeekHead entry payload | 
|  | long long id; | 
|  | long long pos; | 
|  |  | 
|  | // absolute pos of SeekEntry ID | 
|  | long long element_start; | 
|  |  | 
|  | // SeekEntry ID size + size size + payload | 
|  | long long element_size; | 
|  | }; | 
|  |  | 
|  | int GetCount() const; | 
|  | const Entry* GetEntry(int idx) const; | 
|  |  | 
|  | struct VoidElement { | 
|  | // absolute pos of Void ID | 
|  | long long element_start; | 
|  |  | 
|  | // ID size + size size + payload size | 
|  | long long element_size; | 
|  | }; | 
|  |  | 
|  | int GetVoidElementCount() const; | 
|  | const VoidElement* GetVoidElement(int idx) const; | 
|  |  | 
|  | private: | 
|  | Entry* m_entries; | 
|  | int m_entry_count; | 
|  |  | 
|  | VoidElement* m_void_elements; | 
|  | int m_void_element_count; | 
|  |  | 
|  | static bool ParseEntry(IMkvReader*, | 
|  | long long pos,  // payload | 
|  | long long size, Entry*); | 
|  | }; | 
|  |  | 
|  | class Cues; | 
|  | class CuePoint { | 
|  | friend class Cues; | 
|  |  | 
|  | CuePoint(long, long long); | 
|  | ~CuePoint(); | 
|  |  | 
|  | CuePoint(const CuePoint&); | 
|  | CuePoint& operator=(const CuePoint&); | 
|  |  | 
|  | public: | 
|  | long long m_element_start; | 
|  | long long m_element_size; | 
|  |  | 
|  | bool Load(IMkvReader*); | 
|  |  | 
|  | long long GetTimeCode() const;  // absolute but unscaled | 
|  | long long GetTime(const Segment*) const;  // absolute and scaled (ns units) | 
|  |  | 
|  | struct TrackPosition { | 
|  | long long m_track; | 
|  | long long m_pos;  // of cluster | 
|  | long long m_block; | 
|  | // codec_state  //defaults to 0 | 
|  | // reference = clusters containing req'd referenced blocks | 
|  | //  reftime = timecode of the referenced block | 
|  |  | 
|  | bool Parse(IMkvReader*, long long, long long); | 
|  | }; | 
|  |  | 
|  | const TrackPosition* Find(const Track*) const; | 
|  |  | 
|  | private: | 
|  | const long m_index; | 
|  | long long m_timecode; | 
|  | TrackPosition* m_track_positions; | 
|  | size_t m_track_positions_count; | 
|  | }; | 
|  |  | 
|  | class Cues { | 
|  | friend class Segment; | 
|  |  | 
|  | Cues(Segment*, long long start, long long size, long long element_start, | 
|  | long long element_size); | 
|  | ~Cues(); | 
|  |  | 
|  | Cues(const Cues&); | 
|  | Cues& operator=(const Cues&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  | const long long m_start; | 
|  | const long long m_size; | 
|  | const long long m_element_start; | 
|  | const long long m_element_size; | 
|  |  | 
|  | bool Find(  // lower bound of time_ns | 
|  | long long time_ns, const Track*, const CuePoint*&, | 
|  | const CuePoint::TrackPosition*&) const; | 
|  |  | 
|  | const CuePoint* GetFirst() const; | 
|  | const CuePoint* GetLast() const; | 
|  | const CuePoint* GetNext(const CuePoint*) const; | 
|  |  | 
|  | const BlockEntry* GetBlock(const CuePoint*, | 
|  | const CuePoint::TrackPosition*) const; | 
|  |  | 
|  | bool LoadCuePoint() const; | 
|  | long GetCount() const;  // loaded only | 
|  | // long GetTotal() const;  //loaded + preloaded | 
|  | bool DoneParsing() const; | 
|  |  | 
|  | private: | 
|  | bool Init() const; | 
|  | bool PreloadCuePoint(long&, long long) const; | 
|  |  | 
|  | mutable CuePoint** m_cue_points; | 
|  | mutable long m_count; | 
|  | mutable long m_preload_count; | 
|  | mutable long long m_pos; | 
|  | }; | 
|  |  | 
|  | class Cluster { | 
|  | friend class Segment; | 
|  |  | 
|  | Cluster(const Cluster&); | 
|  | Cluster& operator=(const Cluster&); | 
|  |  | 
|  | public: | 
|  | Segment* const m_pSegment; | 
|  |  | 
|  | public: | 
|  | static Cluster* Create(Segment*, | 
|  | long index,  // index in segment | 
|  | long long off);  // offset relative to segment | 
|  | // long long element_size); | 
|  |  | 
|  | Cluster();  // EndOfStream | 
|  | ~Cluster(); | 
|  |  | 
|  | bool EOS() const; | 
|  |  | 
|  | long long GetTimeCode() const;  // absolute, but not scaled | 
|  | long long GetTime() const;  // absolute, and scaled (nanosecond units) | 
|  | long long GetFirstTime() const;  // time (ns) of first (earliest) block | 
|  | long long GetLastTime() const;  // time (ns) of last (latest) block | 
|  |  | 
|  | long GetFirst(const BlockEntry*&) const; | 
|  | long GetLast(const BlockEntry*&) const; | 
|  | long GetNext(const BlockEntry* curr, const BlockEntry*& next) const; | 
|  |  | 
|  | const BlockEntry* GetEntry(const Track*, long long ns = -1) const; | 
|  | const BlockEntry* GetEntry(const CuePoint&, | 
|  | const CuePoint::TrackPosition&) const; | 
|  | // const BlockEntry* GetMaxKey(const VideoTrack*) const; | 
|  |  | 
|  | //    static bool HasBlockEntries(const Segment*, long long); | 
|  |  | 
|  | static long HasBlockEntries(const Segment*, long long idoff, long long& pos, | 
|  | long& size); | 
|  |  | 
|  | long GetEntryCount() const; | 
|  |  | 
|  | long Load(long long& pos, long& size) const; | 
|  |  | 
|  | long Parse(long long& pos, long& size) const; | 
|  | long GetEntry(long index, const mkvparser::BlockEntry*&) const; | 
|  |  | 
|  | protected: | 
|  | Cluster(Segment*, long index, long long element_start); | 
|  | // long long element_size); | 
|  |  | 
|  | public: | 
|  | const long long m_element_start; | 
|  | long long GetPosition() const;  // offset relative to segment | 
|  |  | 
|  | long GetIndex() const; | 
|  | long long GetElementSize() const; | 
|  | // long long GetPayloadSize() const; | 
|  |  | 
|  | // long long Unparsed() const; | 
|  |  | 
|  | private: | 
|  | long m_index; | 
|  | mutable long long m_pos; | 
|  | // mutable long long m_size; | 
|  | mutable long long m_element_size; | 
|  | mutable long long m_timecode; | 
|  | mutable BlockEntry** m_entries; | 
|  | mutable long m_entries_size; | 
|  | mutable long m_entries_count; | 
|  |  | 
|  | long ParseSimpleBlock(long long, long long&, long&); | 
|  | long ParseBlockGroup(long long, long long&, long&); | 
|  |  | 
|  | long CreateBlock(long long id, long long pos, long long size, | 
|  | long long discard_padding); | 
|  | long CreateBlockGroup(long long start_offset, long long size, | 
|  | long long discard_padding); | 
|  | long CreateSimpleBlock(long long, long long); | 
|  | }; | 
|  |  | 
|  | class Segment { | 
|  | friend class Cues; | 
|  | friend class Track; | 
|  | friend class VideoTrack; | 
|  |  | 
|  | Segment(const Segment&); | 
|  | Segment& operator=(const Segment&); | 
|  |  | 
|  | private: | 
|  | Segment(IMkvReader*, long long elem_start, | 
|  | // long long elem_size, | 
|  | long long pos, long long size); | 
|  |  | 
|  | public: | 
|  | IMkvReader* const m_pReader; | 
|  | const long long m_element_start; | 
|  | // const long long m_element_size; | 
|  | const long long m_start;  // posn of segment payload | 
|  | const long long m_size;  // size of segment payload | 
|  | Cluster m_eos;  // TODO: make private? | 
|  |  | 
|  | static long long CreateInstance(IMkvReader*, long long, Segment*&); | 
|  | ~Segment(); | 
|  |  | 
|  | long Load();  // loads headers and all clusters | 
|  |  | 
|  | // for incremental loading | 
|  | // long long Unparsed() const; | 
|  | bool DoneParsing() const; | 
|  | long long ParseHeaders();  // stops when first cluster is found | 
|  | // long FindNextCluster(long long& pos, long& size) const; | 
|  | long LoadCluster(long long& pos, long& size);  // load one cluster | 
|  | long LoadCluster(); | 
|  |  | 
|  | long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos, | 
|  | long& size); | 
|  |  | 
|  | const SeekHead* GetSeekHead() const; | 
|  | const Tracks* GetTracks() const; | 
|  | const SegmentInfo* GetInfo() const; | 
|  | const Cues* GetCues() const; | 
|  | const Chapters* GetChapters() const; | 
|  | const Tags* GetTags() const; | 
|  |  | 
|  | long long GetDuration() const; | 
|  |  | 
|  | unsigned long GetCount() const; | 
|  | const Cluster* GetFirst() const; | 
|  | const Cluster* GetLast() const; | 
|  | const Cluster* GetNext(const Cluster*); | 
|  |  | 
|  | const Cluster* FindCluster(long long time_nanoseconds) const; | 
|  | // const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; | 
|  |  | 
|  | const Cluster* FindOrPreloadCluster(long long pos); | 
|  |  | 
|  | long ParseCues(long long cues_off,  // offset relative to start of segment | 
|  | long long& parse_pos, long& parse_len); | 
|  |  | 
|  | private: | 
|  | long long m_pos;  // absolute file posn; what has been consumed so far | 
|  | Cluster* m_pUnknownSize; | 
|  |  | 
|  | SeekHead* m_pSeekHead; | 
|  | SegmentInfo* m_pInfo; | 
|  | Tracks* m_pTracks; | 
|  | Cues* m_pCues; | 
|  | Chapters* m_pChapters; | 
|  | Tags* m_pTags; | 
|  | Cluster** m_clusters; | 
|  | long m_clusterCount;  // number of entries for which m_index >= 0 | 
|  | long m_clusterPreloadCount;  // number of entries for which m_index < 0 | 
|  | long m_clusterSize;  // array size | 
|  |  | 
|  | long DoLoadCluster(long long&, long&); | 
|  | long DoLoadClusterUnknownSize(long long&, long&); | 
|  | long DoParseNext(const Cluster*&, long long&, long&); | 
|  |  | 
|  | bool AppendCluster(Cluster*); | 
|  | bool PreloadCluster(Cluster*, ptrdiff_t); | 
|  |  | 
|  | // void ParseSeekHead(long long pos, long long size); | 
|  | // void ParseSeekEntry(long long pos, long long size); | 
|  | // void ParseCues(long long); | 
|  |  | 
|  | const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&); | 
|  | }; | 
|  |  | 
|  | }  // namespace mkvparser | 
|  |  | 
|  | inline long mkvparser::Segment::LoadCluster() { | 
|  | long long pos; | 
|  | long size; | 
|  |  | 
|  | return LoadCluster(pos, size); | 
|  | } | 
|  |  | 
|  | #endif  // MKVPARSER_MKVPARSER_H_ |