| // 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_ |