68833c7f85
git log --no-merges 32d5ac4..9732ae9 9732ae9 EbmlElementSize: quiet uint64->int32 conv warning da04eba SetProjectionPrivate: quiet uint64->size_t conv warning 6db32d5 mkvparser,Projection::Parse: fix int->bool conv 3bb0dfa cosmetics: fix a couple lint warnings 0e179d6 update .clang-format fc5f88d Fix temp files being left on system. c04a134 Add support for overriding PixelWidth and PixelHeight. c0160e0 Add support to explicitly set segment duration. 02bc809 Add support to estimate file duration. c97e3e7 Add support to output sub-sample encryption information. 26f4344 MakeUID: quiet unused param warning in Android builds d6af52a Change check to fix compile error. 1720020 webm_parser: Add Mesh value for ProjectionType 78f2c5a webm_parser: Use ./ prefix for includes da62f65 webm_parser: Remove webm/ prefix from public includes e15e8f2 webm_parser: Update README build instructions 5023f2b mkvmuxer: Fix Colour::Valid() cf16204 mkvmuxer_tests: Actually test cue points in the cue point test. 93e9fb3 Validate Colour element values. 8036925 mkvparser_tests: Add Projection element test. f52d38c mkvparser_tests: Add Colour element test. 826436a mkvparser: minor SeekHead::Entry clean up. 24fb44a mkvmuxer_tests: Add Projection element test. 1e0a8ea mkvmuxer_tests: Add Colour element test. 0278616 mkvmuxer: Colour accessors/mutators. 2346f8f Add mkvparser wrapper functions. 54d6b6b webm_info: Add Projection element support. 65fee06 mkvmuxer_sample: Add support for Projection element. 9a3f2b5 mkvparser_sample: Add support for Projection element. 41e814a mkvparser: Add Projection element support. 483a0ff mkvmuxer: Add Projection element support. 676a713 Add support for the Projection element 725f362 mkvmuxer: Fix memory leak when Colour is set multiple times. fa182de mkvparser_sample: Add output of audio track codec private size. 8f521f2 mkvparser_tests: Add invalid BlockGroup test. 39137d7 Remove docs saying binary elements default to 0 80685d3 Do not skip over unknown elements at the root level c147504 Fix legacy Makefile. 58711e8 mkvparser_sample: Fix version info string. 837746f mkvparser_tests: Add invalid block test. 207cd80 Disambiguate sample sources and targets. a112d71 mkvparser_tests: Refactor invalid file loading code. 5dea33e Disambiguate test source and target names. 125049e parser_tests: Add another truncated chapter string test. 1de8d4c parser_tests: Add truncated chapter string test. ff8c2b6 parser_tests: Move cue validation to test_util. 4b0690f parser_tests: Add invalid lacing test. 9828e39 mkvmuxer: Set default doc type version to 4. 5495a59 webm_parser: Reference more files in CMakeLists.txt. 0c0ecd0 vpxpes_parser: Add start code emulation prevention support. 639a4bc webm2pes: Remove debug printfs(). 9a51102 webm2pes: fflush() in the correct conversion function. dc7f155 webm2pes: Track total bytes written. d518128 webm_parser: Enable usage of werror. e1fe762 webm2pes: Add test for mux/demux of large input. 1b24a79 vpxpes_parser: Read and store PTS when present. 6cf0a0f vpxpes_parser: Store frame payloads. 25d2602 webm_parser: Convert style to match the rest of libwebm 24be76d webm2pes: Replace VpxFrame with VideoFrame. b451c3b Add a basic video frame storage class. 05c90eb libwebm_util: Clarify error text in superframe parser. e6415af webm2pes: Make WritePesPacket() a public method. 8f840dd webm2pes: Move frame read out of PES packet write method. 448af97 webm2pes: Restore frame fragmentation support. f8bb714 cmake: Integrate new parsing API and tests. cb8ce0b Add a new incremental parsing API 900d322 vpxpes_parser/webm2pes: BCMV and PTS fixes. 4b73545 webm2pes: Add start code emulation prevention. 82903f3 Add column tiles and frame parallel to webm_info 5d91edf style_clean_up: Remove unnecessary parentheses a95aa4b vp9_level_stats: correct total_uncompressed_bits_ calculation f46566f mkvreader: Fix shorten-64-to-32 warning in 32 bit builds. 76630ca mkvwriter: Fix shorten-64-to-32 warning in 32 bit builds. a8ffbd4 webm2pes: Fix format specifier warnings. faf89d4 Add MaxLumaSampleRate grace percent to stats. d31e6c9 Fix profile 2 in vp9_header_parser. bd3ab3a Add flag to estimate last frame's duration to stats. c182ed9 Fix lint issue in hdr_util.h cc62ecd Add test for Cluster memory leak 196708a Change MaxLumaSampleRate to be based on frame resolution. cbd676b mkvmuxer: Fix leak when a Cluster isn't finalized 9a235e0 mkvmuxer: Set doctype to matroska when muxing non-WebM codecs. 47f2843 Add parsing support for new features in CodecPrivate. e3c9576 Add VP9 level output to webm_info. 5cf549f cmake: Log compiler flag at check time. bbaaf2d Add class to gather VP9 level stats. 8bb68c2 Add file to parse data from VP9 frames. 296429a Add support to parse VP9 profile. df3412f Add support for setting VP9 profile and level to sample_muxer. 87832d4 mkvmuxer: Fix Segment::Finalize in kLive mode 6df3e56 mkvmuxerutil.hpp: Add using directives for overloaded size utils. ec47928 mkvmuxerutil: Revert to using mkvmuxertypes. a1dc4f2 Fix parsing of VP9 level. 4e3d037 Add support to output Colour elements to webm_info. d3656fd muxer_tests: ignore iwyu re gtest-message.h e76dd5e Fix file name in mkvmuxertypes shim. 1be5889 Add temporary include shims at old file locations. 039df94 Add TEST_TMPDIR environment variable Change-Id: I84bc1401b0aad71ad6727b687f1bede9953a7a08
1146 lines
30 KiB
C++
1146 lines
30 KiB
C++
// 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;
|
|
|
|
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;
|
|
|
|
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_
|