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