Add support for encryption elements.

Added support for the ContentEncoding element to be added to a
Track element for muxing. Currently only one ContentEncoding may
be added. The ContentEncoding must be encryption of the whole
frame with AES.
Added support for parsing the ConentEncoding elements. Currently
the parser does not parse any ContentCompression elements.

Change-Id: Ie199116a1bcc18a0c2b5eea3dba6622887c108c8
This commit is contained in:
Frank Galligan 2011-10-10 14:25:05 -04:00
parent 23808a7ba4
commit 4affedd0a7
5 changed files with 766 additions and 4 deletions

View File

@ -259,6 +259,124 @@ bool Cues::Write(IMkvWriter* writer) const {
return true;
}
///////////////////////////////////////////////////////////////
//
// ContentEncoding Class
ContentEncoding::ContentEncoding()
: enc_algo_(5),
enc_key_id_(NULL),
encoding_order_(0),
encoding_scope_(1),
encoding_type_(1),
enc_key_id_length_(0) {
}
ContentEncoding::~ContentEncoding() {
delete [] enc_key_id_;
}
bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
assert(id);
assert(length > 0);
delete [] enc_key_id_;
enc_key_id_ = new (std::nothrow) uint8[static_cast<size_t>(length)];
if (!enc_key_id_)
return false;
memcpy(enc_key_id_, id, static_cast<size_t>(length));
enc_key_id_length_ = length;
return true;
}
uint64 ContentEncoding::Size() const {
const uint64 encryption_size = EncryptionSize();
const uint64 encoding_size = EncodingSize(0, encryption_size);
const uint64 encodings_size = EbmlElementSize(kMkvContentEncoding,
encoding_size,
true) +
encoding_size;
return encodings_size;
}
bool ContentEncoding::Write(IMkvWriter* writer) const {
const uint64 encryption_size = EncryptionSize();
const uint64 encoding_size = EncodingSize(0, encryption_size);
const uint64 size = EbmlElementSize(kMkvContentEncoding,
encoding_size,
true) +
encoding_size;
const int64 payload_position = writer->Position();
if (payload_position < 0)
return false;
if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
return false;
if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
return false;
if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
return false;
if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
return false;
if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
return false;
if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
return false;
if (!WriteEbmlElement(writer,
kMkvContentEncKeyID,
enc_key_id_,
enc_key_id_length_))
return false;
const int64 stop_position = writer->Position();
if (stop_position < 0)
return false;
assert(stop_position - payload_position == static_cast<int64>(size));
return true;
}
uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
uint64 encryption_size) const {
// TODO(fgalligan): Add support for compression settings.
assert(compresion_size == 0);
uint64 encoding_size = 0;
if (encryption_size > 0) {
encoding_size += EbmlElementSize(kMkvContentEncryption,
encryption_size,
true) +
encryption_size;
}
encoding_size += EbmlElementSize(kMkvContentEncodingType,
encoding_type_,
false);
encoding_size += EbmlElementSize(kMkvContentEncodingScope,
encoding_scope_,
false);
encoding_size += EbmlElementSize(kMkvContentEncodingOrder,
encoding_order_,
false);
return encoding_size;
}
uint64 ContentEncoding::EncryptionSize() const {
uint64 encryption_size = EbmlElementSize(kMkvContentEncKeyID,
enc_key_id_,
enc_key_id_length_,
false);
encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_, false);
return encryption_size;
}
///////////////////////////////////////////////////////////////
//
// Track Class
@ -271,12 +389,59 @@ Track::Track()
number_(0),
type_(0),
uid_(MakeUID()),
codec_private_length_(0) {
codec_private_length_(0),
content_encoding_entries_(NULL),
content_encoding_entries_size_(0) {
}
Track::~Track() {
delete [] codec_id_;
delete [] codec_private_;
if (content_encoding_entries_) {
for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
ContentEncoding* const encoding = content_encoding_entries_[i];
delete encoding;
}
delete [] content_encoding_entries_;
}
}
bool Track::AddContentEncoding() {
const uint32 count = content_encoding_entries_size_ + 1;
ContentEncoding** const content_encoding_entries =
new (std::nothrow) ContentEncoding*[count];
if (!content_encoding_entries)
return false;
ContentEncoding* const content_encoding =
new (std::nothrow) ContentEncoding();
if (!content_encoding) {
delete [] content_encoding_entries;
return false;
}
for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
content_encoding_entries[i] = content_encoding_entries_[i];
}
delete [] content_encoding_entries_;
content_encoding_entries_ = content_encoding_entries;
content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
content_encoding_entries_size_ = count;
return true;
}
ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
if (content_encoding_entries_ == NULL)
return NULL;
if (index >= content_encoding_entries_size_)
return NULL;
return content_encoding_entries_[index];
}
uint64 Track::PayloadSize() const {
@ -295,6 +460,19 @@ uint64 Track::PayloadSize() const {
if (name_)
size += EbmlElementSize(kMkvName, name_, false);
if (content_encoding_entries_size_ > 0) {
uint64 content_encodings_size = 0;
for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
ContentEncoding* const encoding = content_encoding_entries_[i];
content_encodings_size += encoding->Size();
}
size += EbmlElementSize(kMkvContentEncodings,
content_encodings_size,
true) +
content_encodings_size;
}
return size;
}
@ -360,11 +538,33 @@ bool Track::Write(IMkvWriter* writer) const {
return false;
}
const int64 stop_position = writer->Position();
int64 stop_position = writer->Position();
if (stop_position < 0)
return false;
assert(stop_position - payload_position == static_cast<int64>(size));
if (content_encoding_entries_size_ > 0) {
uint64 content_encodings_size = 0;
for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
ContentEncoding* const encoding = content_encoding_entries_[i];
content_encodings_size += encoding->Size();
}
if (!WriteEbmlMasterElement(writer,
kMkvContentEncodings,
content_encodings_size))
return false;
for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
ContentEncoding* const encoding = content_encoding_entries_[i];
if (!encoding->Write(writer))
return false;
}
}
stop_position = writer->Position();
if (stop_position < 0)
return false;
return true;
}

View File

@ -170,6 +170,54 @@ class Cues {
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues);
};
///////////////////////////////////////////////////////////////
// ContentEncoding element
// Elements used to describe if the track data has been encrypted or
// compressed with zlib or header stripping.
// Currently only whole frames can only be encrypted once with AES. This
// dictates that ContentEncodingOrder will be 0, ContentEncodingScope will
// be 1, ContentEncodingType will be 1, and ContentEncAlgo will be 5.
class ContentEncoding {
public:
ContentEncoding();
~ContentEncoding();
uint64 enc_algo() const { return enc_algo_; }
uint64 encoding_order() const { return encoding_order_; }
uint64 encoding_scope() const { return encoding_scope_; }
uint64 encoding_type() const { return encoding_type_; }
// Sets the content encryption id. Copies |length| bytes from |id| to
// |enc_key_id_|. Returns true on success.
bool SetEncryptionID(const uint8* id, uint64 length);
// Returns the size in bytes for the ContentEncoding element.
uint64 Size() const;
// Writes out the ContentEncoding element to |writer|. Returns true on
// success.
bool Write(IMkvWriter* writer) const;
private:
// Returns the size in bytes for the encoding elements.
uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const;
// Returns the size in bytes for the encryption elements.
uint64 EncryptionSize() const;
// Track element names
uint64 enc_algo_;
uint8* enc_key_id_;
uint64 encoding_order_;
uint64 encoding_scope_;
uint64 encoding_type_;
// Size of the ContentEncKeyID data in bytes.
uint64 enc_key_id_length_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
};
///////////////////////////////////////////////////////////////
// Track element.
class Track {
@ -177,6 +225,13 @@ class Track {
Track();
virtual ~Track();
// Adds a ContentEncoding element to the Track. Returns true on success.
virtual bool AddContentEncoding();
// Returns the ContentEncoding by index. Returns NULL if there is no
// ContentEncoding match.
ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
// Returns the size in bytes for the payload of the Track element.
virtual uint64 PayloadSize() const;
@ -204,6 +259,9 @@ class Track {
uint64 uid() const { return uid_; }
uint64 codec_private_length() const { return codec_private_length_; }
uint32 content_encoding_entries_size() const {
return content_encoding_entries_size_;
}
private:
// Returns a random number to be used for the Track UID.
@ -221,6 +279,12 @@ class Track {
// Size of the CodecPrivate data in bytes.
uint64 codec_private_length_;
// ContentEncoding element list.
ContentEncoding** content_encoding_entries_;
// Number of ContentEncoding elements added.
uint32 content_encoding_entries_size_;
// Flag telling if the rand call was seeded.
static bool is_seeded_;

View File

@ -4936,6 +4936,278 @@ const char* SegmentInfo::GetTitleAsUTF8() const
return m_pTitleAsUTF8;
}
///////////////////////////////////////////////////////////////
// ContentEncoding element
ContentEncoding::ContentCompression::ContentCompression()
: algo(0),
settings(NULL) {
}
ContentEncoding::ContentCompression::~ContentCompression() {
delete [] settings;
}
ContentEncoding::ContentEncryption::ContentEncryption()
: algo(0),
key_id(NULL),
key_id_len(0),
signature(NULL),
signature_len(0),
sig_key_id(NULL),
sig_key_id_len(0),
sig_algo(0),
sig_hash_algo(0) {
}
ContentEncoding::ContentEncryption::~ContentEncryption() {
delete [] key_id;
delete [] signature;
delete [] sig_key_id;
}
ContentEncoding::ContentEncoding()
: compression_entries_(NULL),
compression_entries_end_(NULL),
encryption_entries_(NULL),
encryption_entries_end_(NULL),
encoding_order_(0),
encoding_scope_(1),
encoding_type_(0) {
}
ContentEncoding::~ContentEncoding() {
ContentCompression** comp_i = compression_entries_;
ContentCompression** const comp_j = compression_entries_end_;
while (comp_i != comp_j) {
ContentCompression* const comp = *comp_i++;
delete comp;
}
delete [] compression_entries_;
ContentEncryption** enc_i = encryption_entries_;
ContentEncryption** const enc_j = encryption_entries_end_;
while (enc_i != enc_j) {
ContentEncryption* const enc = *enc_i++;
delete enc;
}
delete [] encryption_entries_;
}
const ContentEncoding::ContentCompression*
ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
const ptrdiff_t count = compression_entries_end_ - compression_entries_;
assert(count >= 0);
if (idx >= static_cast<unsigned long>(count))
return NULL;
return compression_entries_[idx];
}
unsigned long ContentEncoding::GetCompressionCount() const {
const ptrdiff_t count = compression_entries_end_ - compression_entries_;
assert(count >= 0);
return static_cast<unsigned long>(count);
}
const ContentEncoding::ContentEncryption*
ContentEncoding::GetEncryptionByIndex(unsigned long idx) const {
const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
assert(count >= 0);
if (idx >= static_cast<unsigned long>(count))
return NULL;
return encryption_entries_[idx];
}
unsigned long ContentEncoding::GetEncryptionCount() const {
const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
assert(count >= 0);
return static_cast<unsigned long>(count);
}
void ContentEncoding::ParseEncryptionEntry(
long long start,
long long size,
IMkvReader* const pReader,
ContentEncryption* const encryption) {
assert(pReader);
assert(encryption);
long long pos = start;
const long long stop = start + size;
while (pos < stop) {
#ifdef _DEBUG
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0); //TODO: handle error case
assert((pos + len) <= stop);
#endif
long long value;
unsigned char* buf;
size_t buf_len;
if (Match(pReader, pos, 0x7E1, value)) {
// ContentEncAlgo
encryption->algo = value;
} else if (Match(pReader, pos, 0x7E2, buf, buf_len)) {
// ContentEncKeyID
encryption->key_id = buf;
encryption->key_id_len = buf_len;
} else if (Match(pReader, pos, 0x7E3, buf, buf_len)) {
// ContentSignature
encryption->signature = buf;
encryption->signature_len = buf_len;
} else if (Match(pReader, pos, 0x7E4, buf, buf_len)) {
// ContentSigKeyID
encryption->sig_key_id = buf;
encryption->sig_key_id_len = buf_len;
} else if (Match(pReader, pos, 0x7E5, value)) {
// ContentSigAlgo
encoding_type_ = value;
} else if (Match(pReader, pos, 0x7E6, value)) {
// ContentSigHashAlgo
encoding_type_ = value;
} else {
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0); //TODO: handle error case
assert((pos + len) <= stop);
pos += len; //consume id
const long long size = ReadUInt(pReader, pos, len);
assert(size >= 0); //TODO: handle error case
assert((pos + len) <= stop);
pos += len; //consume length of size
assert((pos + size) <= stop);
pos += size; //consume payload
assert(pos <= stop);
}
}
}
bool ContentEncoding::ParseContentEncodingEntry(long long start,
long long size,
IMkvReader* const pReader) {
assert(pReader);
long long pos = start;
const long long stop = start + size;
// Count ContentCompression and ContentEncryption elements.
long long pos1 = start;
int compression_count = 0;
int encryption_count = 0;
while (pos1 < stop) {
long len;
const long long id = ReadUInt(pReader, pos1, len);
assert(id >= 0);
assert((pos1 + len) <= stop);
pos1 += len; //consume id
const long long size = ReadUInt(pReader, pos1, len);
assert(size >= 0);
assert((pos1 + len) <= stop);
pos1 += len; //consume length of size
//pos now designates start of element
if (id == 0x1034) // ContentCompression ID
++compression_count;
if (id == 0x1035) // ContentEncryption ID
++encryption_count;
pos1 += size; //consume payload
assert(pos1 <= stop);
}
if (compression_count <= 0 && encryption_count <= 0)
return false;
if (compression_count > 0) {
compression_entries_ = new ContentCompression*[compression_count];
compression_entries_end_ = compression_entries_;
}
if (encryption_count > 0) {
encryption_entries_ = new ContentEncryption*[encryption_count];
encryption_entries_end_ = encryption_entries_;
}
while (pos < stop) {
#ifdef _DEBUG
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0); //TODO: handle error case
assert((pos + len) <= stop);
#endif
long long value;
if (Match(pReader, pos, 0x1031, value)) {
// ContentEncodingOrder
encoding_order_ = value;
} else if (Match(pReader, pos, 0x1032, value)) {
// ContentEncodingScope
encoding_scope_ = value;
assert(encoding_scope_ > 0);
} else if (Match(pReader, pos, 0x1033, value)) {
// ContentEncodingType
encoding_type_ = value;
} else {
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0); //TODO: handle error case
assert((pos + len) <= stop);
pos += len; //consume id
const long long size = ReadUInt(pReader, pos, len);
assert(size >= 0); //TODO: handle error case
assert((pos + len) <= stop);
pos += len; //consume length of size
assert((pos + size) <= stop);
//pos now designates start of payload
if (id == 0x1034) {
// ContentCompression ID
// TODO(fgaligan): Add code to parse ContentCompression elements.
} else if (id == 0x1035) {
// ContentEncryption ID
ContentEncryption* const encryption = new ContentEncryption();
ParseEncryptionEntry(pos, size, pReader, encryption);
*encryption_entries_end_ = encryption;
++encryption_entries_end_;
}
pos += size; //consume payload
assert(pos <= stop);
}
}
assert(pos == stop);
return true;
}
Track::Track(
Segment* pSegment,
const Info& i,
@ -4944,7 +5216,9 @@ Track::Track(
m_pSegment(pSegment),
m_element_start(element_start),
m_element_size(element_size),
m_info(i)
m_info(i),
content_encoding_entries_(NULL),
content_encoding_entries_end_(NULL)
{
}
@ -4952,6 +5226,16 @@ Track::~Track()
{
Info& info = const_cast<Info&>(m_info);
info.Clear();
ContentEncoding** i = content_encoding_entries_;
ContentEncoding** const j = content_encoding_entries_end_;
while (i != j) {
ContentEncoding* const encoding = *i++;
delete encoding;
}
delete [] content_encoding_entries_;
}
Track::Info::Info():
@ -5193,6 +5477,99 @@ long Track::GetNext(
return 1;
}
const ContentEncoding*
Track::GetContentEncodingByIndex(unsigned long idx) const {
const ptrdiff_t count =
content_encoding_entries_end_ - content_encoding_entries_;
assert(count >= 0);
if (idx >= static_cast<unsigned long>(count))
return NULL;
return content_encoding_entries_[idx];
}
unsigned long Track::GetContentEncodingCount() const {
const ptrdiff_t count =
content_encoding_entries_end_ - content_encoding_entries_;
assert(count >= 0);
return static_cast<unsigned long>(count);
}
void Track::ParseContentEncodingsEntry(long long start, long long size) {
IMkvReader* const pReader = m_pSegment->m_pReader;
assert(pReader);
long long pos = start;
const long long stop = start + size;
// Count ContentEncoding elements.
long long pos1 = start;
int count = 0;
while (pos1 < stop) {
long len;
const long long id = ReadUInt(pReader, pos1, len);
assert(id >= 0);
assert((pos1 + len) <= stop);
pos1 += len; //consume id
const long long size = ReadUInt(pReader, pos1, len);
assert(size >= 0);
assert((pos1 + len) <= stop);
pos1 += len; //consume length of size
//pos now designates start of element
if (id == 0x2240) // ContentEncoding ID
++count;
pos1 += size; //consume payload
assert(pos1 <= stop);
}
if (count <= 0)
return;
content_encoding_entries_ = new ContentEncoding*[count];
content_encoding_entries_end_ = content_encoding_entries_;
while (pos < stop) {
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0);
assert((pos + len) <= stop);
pos += len; //consume id
const long long size1 = ReadUInt(pReader, pos, len);
assert(size1 >= 0);
assert((pos + len) <= stop);
pos += len; //consume length of size
//pos now designates start of element
if (id == 0x2240) { // ContentEncoding ID
ContentEncoding* const content_encoding = new ContentEncoding();
if (!content_encoding->ParseContentEncodingEntry(pos, size1, pReader)) {
delete content_encoding;
} else {
*content_encoding_entries_end_ = content_encoding;
++content_encoding_entries_end_;
}
}
pos += size1; //consume payload
assert(pos <= stop);
}
assert(pos == stop);
return;
}
Track::EOSBlock::EOSBlock() :
BlockEntry(NULL, LONG_MIN)
@ -5687,7 +6064,6 @@ unsigned long Tracks::GetTracksCount() const
return static_cast<unsigned long>(result);
}
void Tracks::ParseTrackEntry(
long long start,
long long size,
@ -5710,6 +6086,10 @@ void Tracks::ParseTrackEntry(
audioSettings.start = -1;
audioSettings.size = -1;
Track::Settings content_encodings_settings;
content_encodings_settings.start = -1;
content_encodings_settings.size = -1;
long long lacing = 1; //default is true
while (pos < stop)
@ -5773,6 +6153,11 @@ void Tracks::ParseTrackEntry(
audioSettings.start = start;
audioSettings.size = size;
}
else if (id == 0x2D80) // ContentEncodings id
{
content_encodings_settings.start = start;
content_encodings_settings.size = size;
}
else if (id == 0x33C5) //Track UID
{
assert(size <= 8);
@ -5846,6 +6231,13 @@ void Tracks::ParseTrackEntry(
pTrack = NULL;
}
if (content_encodings_settings.start > 0) {
assert(content_encodings_settings.size > 0);
assert(pTrack);
pTrack->ParseContentEncodingsEntry(content_encodings_settings.start,
content_encodings_settings.size);
}
return;
}

View File

@ -188,6 +188,94 @@ private:
};
///////////////////////////////////////////////////////////////
// ContentEncoding element
// Elements used to describe if the track data has been encrypted or
// compressed with zlib or header stripping.
class ContentEncoding {
public:
ContentEncoding();
~ContentEncoding();
// ContentCompression element names
struct ContentCompression {
ContentCompression();
~ContentCompression();
unsigned long long algo;
unsigned char* settings;
};
// 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;
};
// 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;
// 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 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.
bool ParseContentEncodingEntry(long long start,
long long size,
IMkvReader* const 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.
void ParseEncryptionEntry(long long start,
long long size,
IMkvReader* const pReader,
ContentEncryption* const 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
{
@ -239,6 +327,11 @@ public:
virtual bool VetEntry(const BlockEntry*) const = 0;
virtual long Seek(long long time_ns, const BlockEntry*&) const = 0;
const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
unsigned long GetContentEncodingCount() const;
void ParseContentEncodingsEntry(long long start, long long size);
protected:
Track(
Segment*,
@ -261,6 +354,9 @@ protected:
EOSBlock m_eos;
private:
ContentEncoding** content_encoding_entries_;
ContentEncoding** content_encoding_entries_end_;
};

View File

@ -92,6 +92,16 @@ enum MkvId {
kMkvChannels = 0x9F,
kMkvBitDepth = 0x6264,
//end audio
//ContentEncodings
kMkvContentEncodings = 0x6D80,
kMkvContentEncoding = 0x6240,
kMkvContentEncodingOrder = 0x5031,
kMkvContentEncodingScope = 0x5032,
kMkvContentEncodingType = 0x5033,
kMkvContentEncryption = 0x5035,
kMkvContentEncAlgo = 0x47E1,
kMkvContentEncKeyID = 0x47E2,
//end ContentEncodings
//Cueing Data
kMkvCues = 0x1C53BB6B,
kMkvCuePoint = 0xBB,