| // 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_HPP |
| #define MKVPARSER_HPP |
| |
| #include <cstdlib> |
| #include <cstdio> |
| #include <cstddef> |
| |
| namespace mkvparser |
| { |
| |
| 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(); |
| }; |
| |
| long long GetUIntLength(IMkvReader*, long long, long&); |
| long long ReadUInt(IMkvReader*, long long, long&); |
| 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 len, 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; |
| 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_; |
| }; |
| |
| |
| class VideoTrack : public Track |
| { |
| VideoTrack(const VideoTrack&); |
| VideoTrack& operator=(const VideoTrack&); |
| |
| VideoTrack( |
| Segment*, |
| long long element_start, |
| long long element_size); |
| |
| public: |
| static long Parse( |
| Segment*, |
| const Info&, |
| long long element_start, |
| long long element_size, |
| VideoTrack*&); |
| |
| long long GetWidth() const; |
| long long GetHeight() const; |
| double GetFrameRate() const; |
| |
| bool VetEntry(const BlockEntry*) const; |
| long Seek(long long time_ns, const BlockEntry*&) const; |
| |
| private: |
| long long m_width; |
| long long m_height; |
| double m_rate; |
| |
| }; |
| |
| |
| 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 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 |
| { |
| //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; |
| |
| void 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 |
| |
| void 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; |
| |
| #if 0 |
| bool FindNext( //upper_bound of time_ns |
| long long time_ns, |
| const Track*, |
| const CuePoint*&, |
| const CuePoint::TrackPosition*&) const; |
| #endif |
| |
| 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: |
| void Init() const; |
| void 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); |
| |
| #if 0 |
| //This pair parses one cluster, but only changes the state of the |
| //segment object when the cluster is actually added to the index. |
| long ParseCluster(long long& cluster_pos, long long& new_pos) const; |
| bool AddCluster(long long cluster_pos, long long new_pos); |
| #endif |
| |
| const SeekHead* GetSeekHead() const; |
| const Tracks* GetTracks() const; |
| const SegmentInfo* GetInfo() const; |
| const Cues* GetCues() const; |
| const Chapters* GetChapters() 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; |
| 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&); |
| |
| void AppendCluster(Cluster*); |
| void 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&); |
| |
| }; |
| |
| } //end namespace mkvparser |
| |
| inline long mkvparser::Segment::LoadCluster() |
| { |
| long long pos; |
| long size; |
| |
| return LoadCluster(pos, size); |
| } |
| |
| #endif //MKVPARSER_HPP |