summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVignesh Venkatasubramanian <vigneshv@google.com>2016-04-06 11:16:03 -0700
committerVignesh Venkatasubramanian <vigneshv@google.com>2016-04-13 20:07:21 +0000
commit38d9709fe466cc2065b6e5ac8f8264beb6bc9efd (patch)
tree1b43970c3350699bf5366859f5b40a6ebbcb67b1
parent94ab74f3a64f07f56e4aa046c96bacf97d0d4614 (diff)
downloadandroid_external_libvpx-staging/cm-14.0.tar.gz
android_external_libvpx-staging/cm-14.0.tar.bz2
android_external_libvpx-staging/cm-14.0.zip
libwebm: Pull from upstreamstaging/cm-14.0
Upstream has had some refactoring and hence i'm updating the makefile to reflect those changes. Also adding a README.android documenting the procedure for future updates. Bug: 27681071 Current HEAD: 5c50e310e7050192b952fe588186fd1dadc08b6e Change-Id: I00e1cffd66dc4f6284a9accc8b63f669d7ac7297 (cherry picked from commit 6a8330e5684abb81a14e488ebafa283c085c5c79)
-rw-r--r--libwebm.mk4
-rw-r--r--libwebm/README.android35
-rw-r--r--libwebm/common/webmids.h184
-rw-r--r--libwebm/mkvparser/mkvparser.cc (renamed from libwebm/mkvparser.cpp)942
-rw-r--r--libwebm/mkvparser/mkvparser.h (renamed from libwebm/mkvparser.hpp)107
5 files changed, 913 insertions, 359 deletions
diff --git a/libwebm.mk b/libwebm.mk
index 0528cfb..3afa4a0 100644
--- a/libwebm.mk
+++ b/libwebm.mk
@@ -2,7 +2,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := libwebm/mkvparser.cpp
+LOCAL_SRC_FILES := libwebm/mkvparser/mkvparser.cc
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/libwebm/
LOCAL_MODULE := libwebm
diff --git a/libwebm/README.android b/libwebm/README.android
new file mode 100644
index 0000000..dba2327
--- /dev/null
+++ b/libwebm/README.android
@@ -0,0 +1,35 @@
+Name: libwebm
+URL: http://www.webmproject.org
+
+Commit: 5c50e310e7050192b952fe588186fd1dadc08b6e
+
+Description:
+Contains the sources used to compile libwebm's matroska parser.
+
+The libwebm source is from webmproject.org:
+ https://chromium.googlesource.com/webm/libwebm
+
+Notes on updating libwebm source code:
+
+Please follow these steps to update libvpx source code:
+
+1. Copy over the following files from the the libwebm checkout:
+ - mkvparser/mkvparser.cc
+ - mkvparser/mkvparser.h
+ - common/webmids.h
+
+2. Update README.android (this file) with the upstream hash.
+
+3. Copy the git log summary of changes by using the following in the libwebm
+ checkout: git log --pretty="%h %s" <previous_hash>...<current_hash>
+
+4. Commit the changes. The commit message should look like this:
+
+ libwebm: Pull from upstream
+
+ Current HEAD: <hash>
+
+ git log from upstream:
+ a6b2070 <git commit message 1>
+ 08dabbc <git commit message 2>
+ c29fb02 <git commit message 3>
diff --git a/libwebm/common/webmids.h b/libwebm/common/webmids.h
new file mode 100644
index 0000000..32a0c5f
--- /dev/null
+++ b/libwebm/common/webmids.h
@@ -0,0 +1,184 @@
+// 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 COMMON_WEBMIDS_H_
+#define COMMON_WEBMIDS_H_
+
+namespace libwebm {
+
+enum MkvId {
+ kMkvEBML = 0x1A45DFA3,
+ kMkvEBMLVersion = 0x4286,
+ kMkvEBMLReadVersion = 0x42F7,
+ kMkvEBMLMaxIDLength = 0x42F2,
+ kMkvEBMLMaxSizeLength = 0x42F3,
+ kMkvDocType = 0x4282,
+ kMkvDocTypeVersion = 0x4287,
+ kMkvDocTypeReadVersion = 0x4285,
+ kMkvVoid = 0xEC,
+ kMkvSignatureSlot = 0x1B538667,
+ kMkvSignatureAlgo = 0x7E8A,
+ kMkvSignatureHash = 0x7E9A,
+ kMkvSignaturePublicKey = 0x7EA5,
+ kMkvSignature = 0x7EB5,
+ kMkvSignatureElements = 0x7E5B,
+ kMkvSignatureElementList = 0x7E7B,
+ kMkvSignedElement = 0x6532,
+ // segment
+ kMkvSegment = 0x18538067,
+ // Meta Seek Information
+ kMkvSeekHead = 0x114D9B74,
+ kMkvSeek = 0x4DBB,
+ kMkvSeekID = 0x53AB,
+ kMkvSeekPosition = 0x53AC,
+ // Segment Information
+ kMkvInfo = 0x1549A966,
+ kMkvTimecodeScale = 0x2AD7B1,
+ kMkvDuration = 0x4489,
+ kMkvDateUTC = 0x4461,
+ kMkvTitle = 0x7BA9,
+ kMkvMuxingApp = 0x4D80,
+ kMkvWritingApp = 0x5741,
+ // Cluster
+ kMkvCluster = 0x1F43B675,
+ kMkvTimecode = 0xE7,
+ kMkvPrevSize = 0xAB,
+ kMkvBlockGroup = 0xA0,
+ kMkvBlock = 0xA1,
+ kMkvBlockDuration = 0x9B,
+ kMkvReferenceBlock = 0xFB,
+ kMkvLaceNumber = 0xCC,
+ kMkvSimpleBlock = 0xA3,
+ kMkvBlockAdditions = 0x75A1,
+ kMkvBlockMore = 0xA6,
+ kMkvBlockAddID = 0xEE,
+ kMkvBlockAdditional = 0xA5,
+ kMkvDiscardPadding = 0x75A2,
+ // Track
+ kMkvTracks = 0x1654AE6B,
+ kMkvTrackEntry = 0xAE,
+ kMkvTrackNumber = 0xD7,
+ kMkvTrackUID = 0x73C5,
+ kMkvTrackType = 0x83,
+ kMkvFlagEnabled = 0xB9,
+ kMkvFlagDefault = 0x88,
+ kMkvFlagForced = 0x55AA,
+ kMkvFlagLacing = 0x9C,
+ kMkvDefaultDuration = 0x23E383,
+ kMkvMaxBlockAdditionID = 0x55EE,
+ kMkvName = 0x536E,
+ kMkvLanguage = 0x22B59C,
+ kMkvCodecID = 0x86,
+ kMkvCodecPrivate = 0x63A2,
+ kMkvCodecName = 0x258688,
+ kMkvCodecDelay = 0x56AA,
+ kMkvSeekPreRoll = 0x56BB,
+ // video
+ kMkvVideo = 0xE0,
+ kMkvFlagInterlaced = 0x9A,
+ kMkvStereoMode = 0x53B8,
+ kMkvAlphaMode = 0x53C0,
+ kMkvPixelWidth = 0xB0,
+ kMkvPixelHeight = 0xBA,
+ kMkvPixelCropBottom = 0x54AA,
+ kMkvPixelCropTop = 0x54BB,
+ kMkvPixelCropLeft = 0x54CC,
+ kMkvPixelCropRight = 0x54DD,
+ kMkvDisplayWidth = 0x54B0,
+ kMkvDisplayHeight = 0x54BA,
+ kMkvDisplayUnit = 0x54B2,
+ kMkvAspectRatioType = 0x54B3,
+ kMkvFrameRate = 0x2383E3,
+ // end video
+ // colour
+ kMkvColour = 0x55B0,
+ kMkvMatrixCoefficients = 0x55B1,
+ kMkvBitsPerChannel = 0x55B2,
+ kMkvChromaSubsamplingHorz = 0x55B3,
+ kMkvChromaSubsamplingVert = 0x55B4,
+ kMkvCbSubsamplingHorz = 0x55B5,
+ kMkvCbSubsamplingVert = 0x55B6,
+ kMkvChromaSitingHorz = 0x55B7,
+ kMkvChromaSitingVert = 0x55B8,
+ kMkvRange = 0x55B9,
+ kMkvTransferCharacteristics = 0x55BA,
+ kMkvPrimaries = 0x55BB,
+ kMkvMaxCLL = 0x55BC,
+ kMkvMaxFALL = 0x55BD,
+ // mastering metadata
+ kMkvMasteringMetadata = 0x55D0,
+ kMkvPrimaryRChromaticityX = 0x55D1,
+ kMkvPrimaryRChromaticityY = 0x55D2,
+ kMkvPrimaryGChromaticityX = 0x55D3,
+ kMkvPrimaryGChromaticityY = 0x55D4,
+ kMkvPrimaryBChromaticityX = 0x55D5,
+ kMkvPrimaryBChromaticityY = 0x55D6,
+ kMkvWhitePointChromaticityX = 0x55D7,
+ kMkvWhitePointChromaticityY = 0x55D8,
+ kMkvLuminanceMax = 0x55D9,
+ kMkvLuminanceMin = 0x55DA,
+ // end mastering metadata
+ // end colour
+ // audio
+ kMkvAudio = 0xE1,
+ kMkvSamplingFrequency = 0xB5,
+ kMkvOutputSamplingFrequency = 0x78B5,
+ kMkvChannels = 0x9F,
+ kMkvBitDepth = 0x6264,
+ // end audio
+ // ContentEncodings
+ kMkvContentEncodings = 0x6D80,
+ kMkvContentEncoding = 0x6240,
+ kMkvContentEncodingOrder = 0x5031,
+ kMkvContentEncodingScope = 0x5032,
+ kMkvContentEncodingType = 0x5033,
+ kMkvContentCompression = 0x5034,
+ kMkvContentCompAlgo = 0x4254,
+ kMkvContentCompSettings = 0x4255,
+ kMkvContentEncryption = 0x5035,
+ kMkvContentEncAlgo = 0x47E1,
+ kMkvContentEncKeyID = 0x47E2,
+ kMkvContentSignature = 0x47E3,
+ kMkvContentSigKeyID = 0x47E4,
+ kMkvContentSigAlgo = 0x47E5,
+ kMkvContentSigHashAlgo = 0x47E6,
+ kMkvContentEncAESSettings = 0x47E7,
+ kMkvAESSettingsCipherMode = 0x47E8,
+ kMkvAESSettingsCipherInitData = 0x47E9,
+ // end ContentEncodings
+ // Cueing Data
+ kMkvCues = 0x1C53BB6B,
+ kMkvCuePoint = 0xBB,
+ kMkvCueTime = 0xB3,
+ kMkvCueTrackPositions = 0xB7,
+ kMkvCueTrack = 0xF7,
+ kMkvCueClusterPosition = 0xF1,
+ kMkvCueBlockNumber = 0x5378,
+ // Chapters
+ kMkvChapters = 0x1043A770,
+ kMkvEditionEntry = 0x45B9,
+ kMkvChapterAtom = 0xB6,
+ kMkvChapterUID = 0x73C4,
+ kMkvChapterStringUID = 0x5654,
+ kMkvChapterTimeStart = 0x91,
+ kMkvChapterTimeEnd = 0x92,
+ kMkvChapterDisplay = 0x80,
+ kMkvChapString = 0x85,
+ kMkvChapLanguage = 0x437C,
+ kMkvChapCountry = 0x437E,
+ // Tags
+ kMkvTags = 0x1254C367,
+ kMkvTag = 0x7373,
+ kMkvSimpleTag = 0x67C8,
+ kMkvTagName = 0x45A3,
+ kMkvTagString = 0x4487
+};
+
+} // namespace libwebm
+
+#endif // COMMON_WEBMIDS_H_
diff --git a/libwebm/mkvparser.cpp b/libwebm/mkvparser/mkvparser.cc
index 651dc8f..ff13327 100644
--- a/libwebm/mkvparser.cpp
+++ b/libwebm/mkvparser/mkvparser.cc
@@ -5,26 +5,40 @@
// 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.
+#include "mkvparser/mkvparser.h"
-#include "mkvparser.hpp"
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#include <float.h> // _isnan() / _finite()
+#define MSC_COMPAT
+#endif
#include <cassert>
+#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
+#include <memory>
#include <new>
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
+#include "common/webmids.h"
namespace mkvparser {
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const long long Colour::kValueNotPresent = LLONG_MAX;
+
+#ifdef MSC_COMPAT
+inline bool isnan(double val) { return !!_isnan(val); }
+inline bool isinf(double val) { return !_finite(val); }
+#else
+inline bool isnan(double val) { return std::isnan(val); }
+inline bool isinf(double val) { return std::isinf(val); }
+#endif // MSC_COMPAT
IMkvReader::~IMkvReader() {}
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
- unsigned long long element_size) {
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+ unsigned long long element_size) {
if (num_elements == 0 || element_size == 0)
return NULL;
@@ -32,8 +46,10 @@ template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
const unsigned long long num_bytes = num_elements * element_size;
if (element_size > (kMaxAllocSize / num_elements))
return NULL;
+ if (num_bytes != static_cast<size_t>(num_bytes))
+ return NULL;
- return new (std::nothrow) Type[num_bytes];
+ return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
}
void GetVersion(int& major, int& minor, int& build, int& revision) {
@@ -92,14 +108,65 @@ long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
return result;
}
+// Reads an EBML ID and returns it.
+// An ID must at least 1 byte long, cannot exceed 4, and its value must be
+// greater than 0.
+// See known EBML values and EBMLMaxIDLength:
+// http://www.matroska.org/technical/specs/index.html
+// Returns the ID, or a value less than 0 to report an error while reading the
+// ID.
long long ReadID(IMkvReader* pReader, long long pos, long& len) {
- const long long id = ReadUInt(pReader, pos, len);
- if (id < 0 || len < 1 || len > 4) {
- // An ID must be at least 1 byte long, and cannot exceed 4.
- // See EBMLMaxIDLength: http://www.matroska.org/technical/specs/index.html
+ if (pReader == NULL || pos < 0)
+ return E_FILE_FORMAT_INVALID;
+
+ // Read the first byte. The length in bytes of the ID is determined by
+ // finding the first set bit in the first byte of the ID.
+ unsigned char temp_byte = 0;
+ int read_status = pReader->Read(pos, 1, &temp_byte);
+
+ if (read_status < 0)
+ return E_FILE_FORMAT_INVALID;
+ else if (read_status > 0) // No data to read.
+ return E_BUFFER_NOT_FULL;
+
+ if (temp_byte == 0) // ID length > 8 bytes; invalid file.
+ return E_FILE_FORMAT_INVALID;
+
+ int bit_pos = 0;
+ const int kMaxIdLengthInBytes = 4;
+ const int kCheckByte = 0x80;
+
+ // Find the first bit that's set.
+ bool found_bit = false;
+ for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
+ if ((kCheckByte >> bit_pos) & temp_byte) {
+ found_bit = true;
+ break;
+ }
+ }
+
+ if (!found_bit) {
+ // The value is too large to be a valid ID.
return E_FILE_FORMAT_INVALID;
}
- return id;
+
+ // Read the remaining bytes of the ID (if any).
+ const int id_length = bit_pos + 1;
+ long long ebml_id = temp_byte;
+ for (int i = 1; i < id_length; ++i) {
+ ebml_id <<= 8;
+ read_status = pReader->Read(pos + i, 1, &temp_byte);
+
+ if (read_status < 0)
+ return E_FILE_FORMAT_INVALID;
+ else if (read_status > 0)
+ return E_BUFFER_NOT_FULL;
+
+ ebml_id |= temp_byte;
+ }
+
+ len = id_length;
+ return ebml_id;
}
long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
@@ -214,7 +281,7 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
result = d;
}
- if (std::isinf(result) || std::isnan(result))
+ if (mkvparser::isinf(result) || mkvparser::isnan(result))
return E_FILE_FORMAT_INVALID;
return 0;
@@ -269,7 +336,7 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size,
unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
- const long status = pReader->Read(pos, size, buf);
+ const long status = pReader->Read(pos, static_cast<long>(size), buf);
if (status) {
delete[] str;
@@ -282,9 +349,8 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size,
return 0;
}
-long ParseElementHeader(IMkvReader* pReader, long long& pos,
- long long stop, long long& id,
- long long& size) {
+long ParseElementHeader(IMkvReader* pReader, long long& pos, long long stop,
+ long long& id, long long& size) {
if (stop >= 0 && pos >= stop)
return E_FILE_FORMAT_INVALID;
@@ -308,10 +374,10 @@ long ParseElementHeader(IMkvReader* pReader, long long& pos,
return E_FILE_FORMAT_INVALID;
}
- // Avoid rolling over pos when very close to LONG_LONG_MAX.
+ // Avoid rolling over pos when very close to LLONG_MAX.
const unsigned long long rollover_check =
static_cast<unsigned long long>(pos) + len;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return E_FILE_FORMAT_INVALID;
pos += len; // consume length of size
@@ -390,13 +456,13 @@ bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
unsigned long long rollover_check =
static_cast<unsigned long long>(pos) + len;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return false;
pos += len; // consume length of size of payload
rollover_check = static_cast<unsigned long long>(pos) + size;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return false;
if ((pos + size) > available)
@@ -452,66 +518,45 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
return status;
pos = 0;
- long long end = (available >= 1024) ? 1024 : available;
-
- for (;;) {
- unsigned char b = 0;
-
- while (pos < end) {
- status = pReader->Read(pos, 1, &b);
-
- if (status < 0) // error
- return status;
-
- if (b == 0x1A)
- break;
-
- ++pos;
- }
-
- if (b != 0x1A) {
- if (pos >= 1024)
- return E_FILE_FORMAT_INVALID; // don't bother looking anymore
- if ((total >= 0) && ((total - available) < 5))
- return E_FILE_FORMAT_INVALID;
-
- return available + 5; // 5 = 4-byte ID + 1st byte of size
- }
+ // Scan until we find what looks like the first byte of the EBML header.
+ const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
+ const unsigned char kEbmlByte0 = 0x1A;
+ unsigned char scan_byte = 0;
- if ((total >= 0) && ((total - pos) < 5))
- return E_FILE_FORMAT_INVALID;
-
- if ((available - pos) < 5)
- return pos + 5; // try again later
-
- long len;
+ while (pos < kMaxScanBytes) {
+ status = pReader->Read(pos, 1, &scan_byte);
- const long long result = ReadUInt(pReader, pos, len);
-
- if (result < 0) // error
- return result;
+ if (status < 0) // error
+ return status;
+ else if (status > 0)
+ return E_BUFFER_NOT_FULL;
- if (result == 0x0A45DFA3) { // EBML Header ID
- pos += len; // consume ID
+ if (scan_byte == kEbmlByte0)
break;
- }
- ++pos; // throw away just the 0x1A byte, and try again
+ ++pos;
}
- // pos designates start of size field
+ long len = 0;
+ const long long ebml_id = ReadID(pReader, pos, len);
- // get length of size field
+ if (ebml_id == E_BUFFER_NOT_FULL)
+ return E_BUFFER_NOT_FULL;
- long len;
+ if (len != 4 || ebml_id != libwebm::kMkvEBML)
+ return E_FILE_FORMAT_INVALID;
+
+ // Move read pos forward to the EBML header size field.
+ pos += 4;
+
+ // Read length of size field.
long long result = GetUIntLength(pReader, pos, len);
if (result < 0) // error
- return result;
-
- if (result > 0) // need more data
- return result;
+ return E_FILE_FORMAT_INVALID;
+ else if (result > 0) // need more data
+ return E_BUFFER_NOT_FULL;
if (len < 1 || len > 8)
return E_FILE_FORMAT_INVALID;
@@ -522,8 +567,7 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
if ((available - pos) < len)
return pos + len; // try again later
- // get the EBML header size
-
+ // Read the EBML header size.
result = ReadUInt(pReader, pos, len);
if (result < 0) // error
@@ -539,7 +583,7 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
if ((available - pos) < result)
return pos + result;
- end = pos + result;
+ const long long end = pos + result;
Init();
@@ -551,30 +595,30 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
if (status < 0) // error
return status;
- if (size == 0) // weird
+ if (size == 0)
return E_FILE_FORMAT_INVALID;
- if (id == 0x0286) { // version
+ if (id == libwebm::kMkvEBMLVersion) {
m_version = UnserializeUInt(pReader, pos, size);
if (m_version <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x02F7) { // read version
+ } else if (id == libwebm::kMkvEBMLReadVersion) {
m_readVersion = UnserializeUInt(pReader, pos, size);
if (m_readVersion <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x02F2) { // max id length
+ } else if (id == libwebm::kMkvEBMLMaxIDLength) {
m_maxIdLength = UnserializeUInt(pReader, pos, size);
if (m_maxIdLength <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x02F3) { // max size length
+ } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
m_maxSizeLength = UnserializeUInt(pReader, pos, size);
if (m_maxSizeLength <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x0282) { // doctype
+ } else if (id == libwebm::kMkvDocType) {
if (m_docType)
return E_FILE_FORMAT_INVALID;
@@ -582,12 +626,12 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
if (status) // error
return status;
- } else if (id == 0x0287) { // doctype version
+ } else if (id == libwebm::kMkvDocTypeVersion) {
m_docTypeVersion = UnserializeUInt(pReader, pos, size);
if (m_docTypeVersion <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x0285) { // doctype read version
+ } else if (id == libwebm::kMkvDocTypeReadVersion) {
m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
if (m_docTypeReadVersion <= 0)
@@ -600,6 +644,15 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
if (pos != end)
return E_FILE_FORMAT_INVALID;
+ // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
+ if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
+ return E_FILE_FORMAT_INVALID;
+
+ // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
+ if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
+ m_maxSizeLength > 8)
+ return E_FILE_FORMAT_INVALID;
+
return 0;
}
@@ -732,7 +785,7 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
// Handle "unknown size" for live streaming of webm files.
const long long unknown_size = (1LL << (7 * len)) - 1;
- if (id == 0x08538067) { // Segment ID
+ if (id == libwebm::kMkvSegment) {
if (size == unknown_size)
size = -1;
@@ -742,12 +795,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
else if ((pos + size) > total)
size = -1;
- pSegment = new (std::nothrow) Segment(pReader, idpos,
- // elem_size
- pos, size);
-
- if (pSegment == 0)
- return -1; // generic error
+ pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
+ if (pSegment == NULL)
+ return E_PARSE_FAILED;
return 0; // success
}
@@ -796,9 +846,9 @@ long long Segment::ParseHeaders() {
long long pos = m_pos;
const long long element_start = pos;
- // Avoid rolling over pos when very close to LONG_LONG_MAX.
+ // Avoid rolling over pos when very close to LLONG_MAX.
unsigned long long rollover_check = pos + 1ULL;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return E_FILE_FORMAT_INVALID;
if ((pos + 1) > available)
@@ -827,7 +877,7 @@ long long Segment::ParseHeaders() {
if (id < 0)
return E_FILE_FORMAT_INVALID;
- if (id == 0x0F43B675) // Cluster ID
+ if (id == libwebm::kMkvCluster)
break;
pos += len; // consume ID
@@ -862,9 +912,9 @@ long long Segment::ParseHeaders() {
pos += len; // consume length of size of element
- // Avoid rolling over pos when very close to LONG_LONG_MAX.
+ // Avoid rolling over pos when very close to LLONG_MAX.
rollover_check = static_cast<unsigned long long>(pos) + size;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return E_FILE_FORMAT_INVALID;
const long long element_size = size + pos - element_start;
@@ -879,7 +929,7 @@ long long Segment::ParseHeaders() {
if ((pos + size) > available)
return pos + size;
- if (id == 0x0549A966) { // Segment Info ID
+ if (id == libwebm::kMkvInfo) {
if (m_pInfo)
return E_FILE_FORMAT_INVALID;
@@ -893,7 +943,7 @@ long long Segment::ParseHeaders() {
if (status)
return status;
- } else if (id == 0x0654AE6B) { // Tracks ID
+ } else if (id == libwebm::kMkvTracks) {
if (m_pTracks)
return E_FILE_FORMAT_INVALID;
@@ -907,7 +957,7 @@ long long Segment::ParseHeaders() {
if (status)
return status;
- } else if (id == 0x0C53BB6B) { // Cues ID
+ } else if (id == libwebm::kMkvCues) {
if (m_pCues == NULL) {
m_pCues = new (std::nothrow)
Cues(this, pos, size, element_start, element_size);
@@ -915,7 +965,7 @@ long long Segment::ParseHeaders() {
if (m_pCues == NULL)
return -1;
}
- } else if (id == 0x014D9B74) { // SeekHead ID
+ } else if (id == libwebm::kMkvSeekHead) {
if (m_pSeekHead == NULL) {
m_pSeekHead = new (std::nothrow)
SeekHead(this, pos, size, element_start, element_size);
@@ -928,7 +978,7 @@ long long Segment::ParseHeaders() {
if (status)
return status;
}
- } else if (id == 0x0043A770) { // Chapters ID
+ } else if (id == libwebm::kMkvChapters) {
if (m_pChapters == NULL) {
m_pChapters = new (std::nothrow)
Chapters(this, pos, size, element_start, element_size);
@@ -941,7 +991,7 @@ long long Segment::ParseHeaders() {
if (status)
return status;
}
- } else if (id == 0x0254C367) { // Tags ID
+ } else if (id == libwebm::kMkvTags) {
if (m_pTags == NULL) {
m_pTags = new (std::nothrow)
Tags(this, pos, size, element_start, element_size);
@@ -1020,7 +1070,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((segment_stop >= 0) && ((pos + len) > segment_stop))
@@ -1049,7 +1099,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((segment_stop >= 0) && ((pos + len) > segment_stop))
@@ -1067,7 +1117,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
// pos now points to start of payload
- if (size == 0) { // weird
+ if (size == 0) {
+ // Missing element payload: move on.
m_pos = pos;
continue;
}
@@ -1079,9 +1130,11 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
return E_FILE_FORMAT_INVALID;
}
- if (id == 0x0C53BB6B) { // Cues ID
- if (size == unknown_size)
- return E_FILE_FORMAT_INVALID; // TODO: liberalize
+ if (id == libwebm::kMkvCues) {
+ if (size == unknown_size) {
+ // Cues element of unknown size: Not supported.
+ return E_FILE_FORMAT_INVALID;
+ }
if (m_pCues == NULL) {
const long long element_size = (pos - idpos) + size;
@@ -1095,9 +1148,12 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
continue;
}
- if (id != 0x0F43B675) { // Cluster ID
+ if (id != libwebm::kMkvCluster) {
+ // Besides the Segment, Libwebm allows only cluster elements of unknown
+ // size. Fail the parse upon encountering a non-cluster element reporting
+ // unknown size.
if (size == unknown_size)
- return E_FILE_FORMAT_INVALID; // TODO: liberalize
+ return E_FILE_FORMAT_INVALID;
m_pos = pos + size; // consume payload
continue;
@@ -1336,14 +1392,14 @@ bool Segment::AppendCluster(Cluster* pCluster) {
}
bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
- assert(pCluster);
- assert(pCluster->m_index < 0);
- assert(idx >= m_clusterCount);
+ if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
+ return false;
const long count = m_clusterCount + m_clusterPreloadCount;
long& size = m_clusterSize;
- assert(size >= count);
+ if (size < count)
+ return false;
if (count >= size) {
const long n = (size <= 0) ? 2048 : 2 * size;
@@ -1365,17 +1421,20 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
size = n;
}
- assert(m_clusters);
+ if (m_clusters == NULL)
+ return false;
Cluster** const p = m_clusters + idx;
Cluster** q = m_clusters + count;
- assert(q >= p);
- assert(q < (m_clusters + size));
+ if (q < p || q >= (m_clusters + size))
+ return false;
while (q > p) {
Cluster** const qq = q - 1;
- assert((*qq)->m_index < 0);
+
+ if ((*qq)->m_index >= 0)
+ return false;
*q = *qq;
q = qq;
@@ -1387,10 +1446,8 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
}
long Segment::Load() {
- assert(m_clusters == NULL);
- assert(m_clusterSize == 0);
- assert(m_clusterCount == 0);
- // assert(m_size >= 0);
+ if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
+ return E_PARSE_FAILED;
// Outermost (level 0) segment object has been constructed,
// and pos designates start of payload. We need to find the
@@ -1454,9 +1511,9 @@ long SeekHead::Parse() {
if (status < 0) // error
return status;
- if (id == 0x0DBB) // SeekEntry ID
+ if (id == libwebm::kMkvSeek)
++entry_count;
- else if (id == 0x6C) // Void ID
+ else if (id == libwebm::kMkvVoid)
++void_element_count;
pos += size; // consume payload
@@ -1495,14 +1552,14 @@ long SeekHead::Parse() {
if (status < 0) // error
return status;
- if (id == 0x0DBB) { // SeekEntry ID
+ if (id == libwebm::kMkvSeek) {
if (ParseEntry(pReader, pos, size, pEntry)) {
Entry& e = *pEntry++;
e.element_start = idpos;
e.element_size = (pos + size) - idpos;
}
- } else if (id == 0x6C) { // Void ID
+ } else if (id == libwebm::kMkvVoid) {
VoidElement& e = *pVoidElement++;
e.element_start = idpos;
@@ -1606,7 +1663,7 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
const long long id = ReadID(m_pReader, idpos, len);
- if (id != 0x0C53BB6B) // Cues ID
+ if (id != libwebm::kMkvCues)
return E_FILE_FORMAT_INVALID;
pos += len; // consume ID
@@ -1688,7 +1745,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
if (seekIdId < 0)
return false;
- if (seekIdId != 0x13AB) // SeekID ID
+ if (seekIdId != libwebm::kMkvSeekID)
return false;
if ((pos + len) > stop)
@@ -1730,9 +1787,9 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
pos += seekIdSize; // consume SeekID payload
- const long long seekPosId = ReadUInt(pReader, pos, len);
+ const long long seekPosId = ReadID(pReader, pos, len);
- if (seekPosId != 0x13AC) // SeekPos ID
+ if (seekPosId != libwebm::kMkvSeekPosition)
return false;
if ((pos + len) > stop)
@@ -1842,7 +1899,7 @@ bool Cues::Init() const {
return false;
}
- if (id == 0x3B) { // CuePoint ID
+ if (id == libwebm::kMkvCuePoint) {
if (!PreloadCuePoint(cue_points_size, idpos))
return false;
}
@@ -1917,7 +1974,7 @@ bool Cues::LoadCuePoint() const {
if ((m_pos + size) > stop)
return false;
- if (id != 0x3B) { // CuePoint ID
+ if (id != libwebm::kMkvCuePoint) {
m_pos += size; // consume payload
if (m_pos > stop)
return false;
@@ -2047,8 +2104,8 @@ const CuePoint* Cues::GetLast() const {
}
const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
- if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
- m_cue_points == NULL || m_count < 1) {
+ if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
+ m_count < 1) {
return NULL;
}
@@ -2228,7 +2285,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
long len;
const long long id = ReadID(pReader, pos_, len);
- if (id != 0x3B)
+ if (id != libwebm::kMkvCuePoint)
return false;
pos_ += len; // consume ID
@@ -2268,10 +2325,10 @@ bool CuePoint::Load(IMkvReader* pReader) {
return false;
}
- if (id == 0x33) // CueTime ID
+ if (id == libwebm::kMkvCueTime)
m_timecode = UnserializeUInt(pReader, pos, size);
- else if (id == 0x37) // CueTrackPosition(s) ID
+ else if (id == libwebm::kMkvCueTrackPositions)
++m_track_positions_count;
pos += size; // consume payload
@@ -2310,7 +2367,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
pos += len; // consume Size field
assert((pos + size) <= stop);
- if (id == 0x37) { // CueTrackPosition(s) ID
+ if (id == libwebm::kMkvCueTrackPositions) {
TrackPosition& tp = *p++;
if (!tp.Parse(pReader, pos, size)) {
return false;
@@ -2359,13 +2416,11 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
return false;
}
- if (id == 0x77) // CueTrack ID
+ if (id == libwebm::kMkvCueTrack)
m_track = UnserializeUInt(pReader, pos, size);
-
- else if (id == 0x71) // CueClusterPos ID
+ else if (id == libwebm::kMkvCueClusterPosition)
m_pos = UnserializeUInt(pReader, pos, size);
-
- else if (id == 0x1378) // CueBlockNumber
+ else if (id == libwebm::kMkvCueBlockNumber)
m_block = UnserializeUInt(pReader, pos, size);
pos += size; // consume payload
@@ -2499,7 +2554,7 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
return NULL;
const long long id = ReadID(m_pReader, pos, len);
- if (id != 0x0F43B675) // Cluster ID
+ if (id != libwebm::kMkvCluster)
return NULL;
pos += len; // consume ID
@@ -2556,7 +2611,7 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
if (size == 0) // weird
continue;
- if (id == 0x0F43B675) { // Cluster ID
+ if (id == libwebm::kMkvCluster) {
const long long off_next_ = idpos - m_start;
long long pos_;
@@ -2706,7 +2761,7 @@ long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
const long long id = ReadUInt(m_pReader, pos, len);
- if (id != 0x0F43B675) // weird: not Cluster ID
+ if (id != libwebm::kMkvCluster)
return -1;
pos += len; // consume ID
@@ -2821,7 +2876,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
const long long idpos = pos; // absolute
const long long idoff = pos - m_start; // relative
- const long long id = ReadUInt(m_pReader, idpos, len); // absolute
+ const long long id = ReadID(m_pReader, idpos, len); // absolute
if (id < 0) // error
return static_cast<long>(id);
@@ -2871,7 +2926,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
return E_FILE_FORMAT_INVALID;
}
- if (id == 0x0C53BB6B) { // Cues ID
+ if (id == libwebm::kMkvCues) {
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
@@ -2897,7 +2952,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
continue;
}
- if (id != 0x0F43B675) { // not a Cluster ID
+ if (id != libwebm::kMkvCluster) { // not a Cluster ID
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
@@ -3026,7 +3081,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
return E_BUFFER_NOT_FULL;
const long long idpos = pos;
- const long long id = ReadUInt(m_pReader, idpos, len);
+ const long long id = ReadID(m_pReader, idpos, len);
if (id < 0) // error (or underflow)
return static_cast<long>(id);
@@ -3035,10 +3090,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == 0x0F43B675) // Cluster ID
- break;
-
- if (id == 0x0C53BB6B) // Cues ID
+ if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
break;
pos += len; // consume ID (of sub-element)
@@ -3206,7 +3258,7 @@ long Chapters::Parse() {
if (size == 0) // weird
continue;
- if (id == 0x05B9) { // EditionEntry ID
+ if (id == libwebm::kMkvEditionEntry) {
status = ParseEdition(pos, size);
if (status < 0) // error
@@ -3319,10 +3371,10 @@ long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
if (status < 0) // error
return status;
- if (size == 0) // weird
+ if (size == 0)
continue;
- if (id == 0x36) { // Atom ID
+ if (id == libwebm::kMkvChapterAtom) {
status = ParseAtom(pReader, pos, size);
if (status < 0) // error
@@ -3452,20 +3504,20 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
if (status < 0) // error
return status;
- if (size == 0) // weird
+ if (size == 0) // 0 length payload, skip.
continue;
- if (id == 0x00) { // Display ID
+ if (id == libwebm::kMkvChapterDisplay) {
status = ParseDisplay(pReader, pos, size);
if (status < 0) // error
return status;
- } else if (id == 0x1654) { // StringUID ID
+ } else if (id == libwebm::kMkvChapterStringUID) {
status = UnserializeString(pReader, pos, size, m_string_uid);
if (status < 0) // error
return status;
- } else if (id == 0x33C4) { // UID ID
+ } else if (id == libwebm::kMkvChapterUID) {
long long val;
status = UnserializeInt(pReader, pos, size, val);
@@ -3473,14 +3525,14 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
return status;
m_uid = static_cast<unsigned long long>(val);
- } else if (id == 0x11) { // TimeStart ID
+ } else if (id == libwebm::kMkvChapterTimeStart) {
const long long val = UnserializeUInt(pReader, pos, size);
if (val < 0) // error
return static_cast<long>(val);
m_start_timecode = val;
- } else if (id == 0x12) { // TimeEnd ID
+ } else if (id == libwebm::kMkvChapterTimeEnd) {
const long long val = UnserializeUInt(pReader, pos, size);
if (val < 0) // error
@@ -3605,20 +3657,20 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
if (status < 0) // error
return status;
- if (size == 0) // weird
+ if (size == 0) // No payload.
continue;
- if (id == 0x05) { // ChapterString ID
+ if (id == libwebm::kMkvChapString) {
status = UnserializeString(pReader, pos, size, m_string);
if (status)
return status;
- } else if (id == 0x037C) { // ChapterLanguage ID
+ } else if (id == libwebm::kMkvChapLanguage) {
status = UnserializeString(pReader, pos, size, m_language);
if (status)
return status;
- } else if (id == 0x037E) { // ChapterCountry ID
+ } else if (id == libwebm::kMkvChapCountry) {
status = UnserializeString(pReader, pos, size, m_country);
if (status)
@@ -3671,7 +3723,7 @@ long Tags::Parse() {
if (size == 0) // 0 length tag, read another
continue;
- if (id == 0x3373) { // Tag ID
+ if (id == libwebm::kMkvTag) {
status = ParseTag(pos, size);
if (status < 0)
@@ -3787,7 +3839,7 @@ long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
if (size == 0) // 0 length tag, read another
continue;
- if (id == 0x27C8) { // SimpleTag ID
+ if (id == libwebm::kMkvSimpleTag) {
status = ParseSimpleTag(pReader, pos, size);
if (status < 0)
@@ -3878,12 +3930,12 @@ long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
if (size == 0) // weird
continue;
- if (id == 0x5A3) { // TagName ID
+ if (id == libwebm::kMkvTagName) {
status = UnserializeString(pReader, pos, size, m_tag_name);
if (status)
return status;
- } else if (id == 0x487) { // TagString ID
+ } else if (id == libwebm::kMkvTagString) {
status = UnserializeString(pReader, pos, size, m_tag_string);
if (status)
@@ -3943,12 +3995,12 @@ long SegmentInfo::Parse() {
if (status < 0) // error
return status;
- if (id == 0x0AD7B1) { // Timecode Scale
+ if (id == libwebm::kMkvTimecodeScale) {
m_timecodeScale = UnserializeUInt(pReader, pos, size);
if (m_timecodeScale <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x0489) { // Segment duration
+ } else if (id == libwebm::kMkvDuration) {
const long status = UnserializeFloat(pReader, pos, size, m_duration);
if (status < 0)
@@ -3956,19 +4008,19 @@ long SegmentInfo::Parse() {
if (m_duration < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x0D80) { // MuxingApp
+ } else if (id == libwebm::kMkvMuxingApp) {
const long status =
UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
if (status)
return status;
- } else if (id == 0x1741) { // WritingApp
+ } else if (id == libwebm::kMkvWritingApp) {
const long status =
UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
if (status)
return status;
- } else if (id == 0x3BA9) { // Title
+ } else if (id == libwebm::kMkvTitle) {
const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
if (status)
@@ -3982,7 +4034,7 @@ long SegmentInfo::Parse() {
}
const double rollover_check = m_duration * m_timecodeScale;
- if (rollover_check > LONG_LONG_MAX)
+ if (rollover_check > LLONG_MAX)
return E_FILE_FORMAT_INVALID;
if (pos != stop)
@@ -4123,8 +4175,7 @@ long ContentEncoding::ParseContentEncAESSettingsEntry(
if (status < 0) // error
return status;
- if (id == 0x7E8) {
- // AESSettingsCipherMode
+ if (id == libwebm::kMkvAESSettingsCipherMode) {
aes->cipher_mode = UnserializeUInt(pReader, pos, size);
if (aes->cipher_mode != 1)
return E_FILE_FORMAT_INVALID;
@@ -4155,10 +4206,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
if (status < 0) // error
return status;
- if (id == 0x1034) // ContentCompression ID
+ if (id == libwebm::kMkvContentCompression)
++compression_count;
- if (id == 0x1035) // ContentEncryption ID
+ if (id == libwebm::kMkvContentEncryption)
++encryption_count;
pos += size; // consume payload
@@ -4194,19 +4245,15 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
if (status < 0) // error
return status;
- if (id == 0x1031) {
- // ContentEncodingOrder
+ if (id == libwebm::kMkvContentEncodingOrder) {
encoding_order_ = UnserializeUInt(pReader, pos, size);
- } else if (id == 0x1032) {
- // ContentEncodingScope
+ } else if (id == libwebm::kMkvContentEncodingScope) {
encoding_scope_ = UnserializeUInt(pReader, pos, size);
if (encoding_scope_ < 1)
return -1;
- } else if (id == 0x1033) {
- // ContentEncodingType
+ } else if (id == libwebm::kMkvContentEncodingType) {
encoding_type_ = UnserializeUInt(pReader, pos, size);
- } else if (id == 0x1034) {
- // ContentCompression ID
+ } else if (id == libwebm::kMkvContentCompression) {
ContentCompression* const compression =
new (std::nothrow) ContentCompression();
if (!compression)
@@ -4218,8 +4265,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
return status;
}
*compression_entries_end_++ = compression;
- } else if (id == 0x1035) {
- // ContentEncryption ID
+ } else if (id == libwebm::kMkvContentEncryption) {
ContentEncryption* const encryption =
new (std::nothrow) ContentEncryption();
if (!encryption)
@@ -4260,15 +4306,13 @@ long ContentEncoding::ParseCompressionEntry(long long start, long long size,
if (status < 0) // error
return status;
- if (id == 0x254) {
- // ContentCompAlgo
+ if (id == libwebm::kMkvContentCompAlgo) {
long long algo = UnserializeUInt(pReader, pos, size);
if (algo < 0)
return E_FILE_FORMAT_INVALID;
compression->algo = algo;
valid = true;
- } else if (id == 0x255) {
- // ContentCompSettings
+ } else if (id == libwebm::kMkvContentCompSettings) {
if (size <= 0)
return E_FILE_FORMAT_INVALID;
@@ -4315,13 +4359,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
if (status < 0) // error
return status;
- if (id == 0x7E1) {
- // ContentEncAlgo
+ if (id == libwebm::kMkvContentEncAlgo) {
encryption->algo = UnserializeUInt(pReader, pos, size);
if (encryption->algo != 5)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x7E2) {
- // ContentEncKeyID
+ } else if (id == libwebm::kMkvContentEncKeyID) {
delete[] encryption->key_id;
encryption->key_id = NULL;
encryption->key_id_len = 0;
@@ -4343,8 +4385,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
encryption->key_id = buf;
encryption->key_id_len = buflen;
- } else if (id == 0x7E3) {
- // ContentSignature
+ } else if (id == libwebm::kMkvContentSignature) {
delete[] encryption->signature;
encryption->signature = NULL;
encryption->signature_len = 0;
@@ -4366,8 +4407,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
encryption->signature = buf;
encryption->signature_len = buflen;
- } else if (id == 0x7E4) {
- // ContentSigKeyID
+ } else if (id == libwebm::kMkvContentSigKeyID) {
delete[] encryption->sig_key_id;
encryption->sig_key_id = NULL;
encryption->sig_key_id_len = 0;
@@ -4389,14 +4429,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
encryption->sig_key_id = buf;
encryption->sig_key_id_len = buflen;
- } else if (id == 0x7E5) {
- // ContentSigAlgo
+ } else if (id == libwebm::kMkvContentSigAlgo) {
encryption->sig_algo = UnserializeUInt(pReader, pos, size);
- } else if (id == 0x7E6) {
- // ContentSigHashAlgo
+ } else if (id == libwebm::kMkvContentSigHashAlgo) {
encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
- } else if (id == 0x7E7) {
- // ContentEncAESSettings
+ } else if (id == libwebm::kMkvContentEncAESSettings) {
const long status = ParseContentEncAESSettingsEntry(
pos, size, pReader, &encryption->aes_settings);
if (status)
@@ -4883,7 +4920,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
return status;
// pos now designates start of element
- if (id == 0x2240) // ContentEncoding ID
+ if (id == libwebm::kMkvContentEncoding)
++count;
pos += size; // consume payload
@@ -4908,7 +4945,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
return status;
// pos now designates start of element
- if (id == 0x2240) { // ContentEncoding ID
+ if (id == libwebm::kMkvContentEncoding) {
ContentEncoding* const content_encoding =
new (std::nothrow) ContentEncoding();
if (!content_encoding)
@@ -4940,9 +4977,222 @@ BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
const Block* Track::EOSBlock::GetBlock() const { return NULL; }
+bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
+ long long value_size, bool is_x,
+ PrimaryChromaticity** chromaticity) {
+ if (!reader)
+ return false;
+
+ std::auto_ptr<PrimaryChromaticity> chromaticity_ptr;
+
+ if (!*chromaticity) {
+ chromaticity_ptr.reset(new PrimaryChromaticity());
+ } else {
+ chromaticity_ptr.reset(*chromaticity);
+ }
+
+ if (!chromaticity_ptr.get())
+ return false;
+
+ float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
+
+ double parser_value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, value_size, parser_value);
+
+ *value = static_cast<float>(parser_value);
+
+ if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
+ return false;
+
+ *chromaticity = chromaticity_ptr.release();
+ return true;
+}
+
+bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
+ long long mm_size, MasteringMetadata** mm) {
+ if (!reader || *mm)
+ return false;
+
+ std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+ if (!mm_ptr.get())
+ return false;
+
+ const long long mm_end = mm_start + mm_size;
+ long long read_pos = mm_start;
+
+ while (read_pos < mm_end) {
+ long long child_id = 0;
+ long long child_size = 0;
+
+ const long long status =
+ ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
+ if (status < 0)
+ return false;
+
+ if (child_id == libwebm::kMkvLuminanceMax) {
+ double value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, child_size, value);
+ mm_ptr->luminance_max = static_cast<float>(value);
+ if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
+ mm_ptr->luminance_max > 9999.99) {
+ return false;
+ }
+ } else if (child_id == libwebm::kMkvLuminanceMin) {
+ double value = 0;
+ const long long value_parse_status =
+ UnserializeFloat(reader, read_pos, child_size, value);
+ mm_ptr->luminance_min = static_cast<float>(value);
+ if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
+ mm_ptr->luminance_min > 999.9999) {
+ return false;
+ }
+ } else {
+ bool is_x = false;
+ PrimaryChromaticity** chromaticity;
+ switch (child_id) {
+ case libwebm::kMkvPrimaryRChromaticityX:
+ case libwebm::kMkvPrimaryRChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
+ chromaticity = &mm_ptr->r;
+ break;
+ case libwebm::kMkvPrimaryGChromaticityX:
+ case libwebm::kMkvPrimaryGChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
+ chromaticity = &mm_ptr->g;
+ break;
+ case libwebm::kMkvPrimaryBChromaticityX:
+ case libwebm::kMkvPrimaryBChromaticityY:
+ is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
+ chromaticity = &mm_ptr->b;
+ break;
+ case libwebm::kMkvWhitePointChromaticityX:
+ case libwebm::kMkvWhitePointChromaticityY:
+ is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
+ chromaticity = &mm_ptr->white_point;
+ break;
+ default:
+ return false;
+ }
+ const bool value_parse_status = PrimaryChromaticity::Parse(
+ reader, read_pos, child_size, is_x, chromaticity);
+ if (!value_parse_status)
+ return false;
+ }
+
+ read_pos += child_size;
+ if (read_pos > mm_end)
+ return false;
+ }
+
+ *mm = mm_ptr.release();
+ return true;
+}
+
+bool Colour::Parse(IMkvReader* reader, long long colour_start,
+ long long colour_size, Colour** colour) {
+ if (!reader || *colour)
+ return false;
+
+ std::auto_ptr<Colour> colour_ptr(new Colour());
+ if (!colour_ptr.get())
+ return false;
+
+ const long long colour_end = colour_start + colour_size;
+ long long read_pos = colour_start;
+
+ while (read_pos < colour_end) {
+ long long child_id = 0;
+ long long child_size = 0;
+
+ const long status =
+ ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
+ if (status < 0)
+ return false;
+
+ if (child_id == libwebm::kMkvMatrixCoefficients) {
+ colour_ptr->matrix_coefficients =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->matrix_coefficients < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvBitsPerChannel) {
+ colour_ptr->bits_per_channel =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->bits_per_channel < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
+ colour_ptr->chroma_subsampling_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_subsampling_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
+ colour_ptr->chroma_subsampling_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_subsampling_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
+ colour_ptr->cb_subsampling_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->cb_subsampling_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
+ colour_ptr->cb_subsampling_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->cb_subsampling_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSitingHorz) {
+ colour_ptr->chroma_siting_horz =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_siting_horz < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvChromaSitingVert) {
+ colour_ptr->chroma_siting_vert =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->chroma_siting_vert < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvRange) {
+ colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->range < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvTransferCharacteristics) {
+ colour_ptr->transfer_characteristics =
+ UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->transfer_characteristics < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvPrimaries) {
+ colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->primaries < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMaxCLL) {
+ colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->max_cll < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMaxFALL) {
+ colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
+ if (colour_ptr->max_fall < 0)
+ return false;
+ } else if (child_id == libwebm::kMkvMasteringMetadata) {
+ if (!MasteringMetadata::Parse(reader, read_pos, child_size,
+ &colour_ptr->mastering_metadata))
+ return false;
+ } else {
+ return false;
+ }
+
+ read_pos += child_size;
+ if (read_pos > colour_end)
+ return false;
+ }
+ *colour = colour_ptr.release();
+ return true;
+}
+
VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
long long element_size)
- : Track(pSegment, element_start, element_size) {}
+ : Track(pSegment, element_start, element_size), m_colour(NULL) {}
+
+VideoTrack::~VideoTrack() { delete m_colour; }
long VideoTrack::Parse(Segment* pSegment, const Info& info,
long long element_start, long long element_size,
@@ -4973,6 +5223,8 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
const long long stop = pos + s.size;
+ Colour* colour = NULL;
+
while (pos < stop) {
long long id, size;
@@ -4981,37 +5233,37 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
if (status < 0) // error
return status;
- if (id == 0x30) { // pixel width
+ if (id == libwebm::kMkvPixelWidth) {
width = UnserializeUInt(pReader, pos, size);
if (width <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x3A) { // pixel height
+ } else if (id == libwebm::kMkvPixelHeight) {
height = UnserializeUInt(pReader, pos, size);
if (height <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x14B0) { // display width
+ } else if (id == libwebm::kMkvDisplayWidth) {
display_width = UnserializeUInt(pReader, pos, size);
if (display_width <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x14BA) { // display height
+ } else if (id == libwebm::kMkvDisplayHeight) {
display_height = UnserializeUInt(pReader, pos, size);
if (display_height <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x14B2) { // display unit
+ } else if (id == libwebm::kMkvDisplayUnit) {
display_unit = UnserializeUInt(pReader, pos, size);
if (display_unit < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x13B8) { // stereo mode
+ } else if (id == libwebm::kMkvStereoMode) {
stereo_mode = UnserializeUInt(pReader, pos, size);
if (stereo_mode < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x0383E3) { // frame rate
+ } else if (id == libwebm::kMkvFrameRate) {
const long status = UnserializeFloat(pReader, pos, size, rate);
if (status < 0)
@@ -5019,6 +5271,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
if (rate <= 0)
return E_FILE_FORMAT_INVALID;
+ } else if (id == libwebm::kMkvColour) {
+ if (!Colour::Parse(pReader, pos, size, &colour))
+ return E_FILE_FORMAT_INVALID;
}
pos += size; // consume payload
@@ -5049,6 +5304,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
pTrack->m_display_unit = display_unit;
pTrack->m_stereo_mode = stereo_mode;
pTrack->m_rate = rate;
+ pTrack->m_colour = colour;
pResult = pTrack;
return 0; // success
@@ -5147,6 +5403,8 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
return 0;
}
+Colour* VideoTrack::GetColour() const { return m_colour; }
+
long long VideoTrack::GetWidth() const { return m_width; }
long long VideoTrack::GetHeight() const { return m_height; }
@@ -5201,7 +5459,7 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
if (status < 0) // error
return status;
- if (id == 0x35) { // Sample Rate
+ if (id == libwebm::kMkvSamplingFrequency) {
status = UnserializeFloat(pReader, pos, size, rate);
if (status < 0)
@@ -5209,12 +5467,12 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
if (rate <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x1F) { // Channel Count
+ } else if (id == libwebm::kMkvChannels) {
channels = UnserializeUInt(pReader, pos, size);
if (channels <= 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x2264) { // Bit Depth
+ } else if (id == libwebm::kMkvBitDepth) {
bit_depth = UnserializeUInt(pReader, pos, size);
if (bit_depth <= 0)
@@ -5287,7 +5545,7 @@ long Tracks::Parse() {
if (size == 0) // weird
continue;
- if (id == 0x2E) // TrackEntry ID
+ if (id == libwebm::kMkvTrackEntry)
++count;
pos += size; // consume payload
@@ -5329,13 +5587,12 @@ long Tracks::Parse() {
const long long element_size = payload_stop - element_start;
- if (id == 0x2E) { // TrackEntry ID
+ if (id == libwebm::kMkvTrackEntry) {
Track*& pTrack = *m_trackEntriesEnd;
pTrack = NULL;
const long status = ParseTrackEntry(pos, payload_size, element_start,
element_size, pTrack);
-
if (status)
return status;
@@ -5406,16 +5663,16 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
const long long start = pos;
- if (id == 0x60) { // VideoSettings ID
+ if (id == libwebm::kMkvVideo) {
v.start = start;
v.size = size;
- } else if (id == 0x61) { // AudioSettings ID
+ } else if (id == libwebm::kMkvAudio) {
a.start = start;
a.size = size;
- } else if (id == 0x2D80) { // ContentEncodings ID
+ } else if (id == libwebm::kMkvContentEncodings) {
e.start = start;
e.size = size;
- } else if (id == 0x33C5) { // Track UID
+ } else if (id == libwebm::kMkvTrackUID) {
if (size > 8)
return E_FILE_FORMAT_INVALID;
@@ -5437,49 +5694,49 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
++pos_;
}
- } else if (id == 0x57) { // Track Number
+ } else if (id == libwebm::kMkvTrackNumber) {
const long long num = UnserializeUInt(pReader, pos, size);
if ((num <= 0) || (num > 127))
return E_FILE_FORMAT_INVALID;
info.number = static_cast<long>(num);
- } else if (id == 0x03) { // Track Type
+ } else if (id == libwebm::kMkvTrackType) {
const long long type = UnserializeUInt(pReader, pos, size);
if ((type <= 0) || (type > 254))
return E_FILE_FORMAT_INVALID;
info.type = static_cast<long>(type);
- } else if (id == 0x136E) { // Track Name
+ } else if (id == libwebm::kMkvName) {
const long status =
UnserializeString(pReader, pos, size, info.nameAsUTF8);
if (status)
return status;
- } else if (id == 0x02B59C) { // Track Language
+ } else if (id == libwebm::kMkvLanguage) {
const long status = UnserializeString(pReader, pos, size, info.language);
if (status)
return status;
- } else if (id == 0x03E383) { // Default Duration
+ } else if (id == libwebm::kMkvDefaultDuration) {
const long long duration = UnserializeUInt(pReader, pos, size);
if (duration < 0)
return E_FILE_FORMAT_INVALID;
info.defaultDuration = static_cast<unsigned long long>(duration);
- } else if (id == 0x06) { // CodecID
+ } else if (id == libwebm::kMkvCodecID) {
const long status = UnserializeString(pReader, pos, size, info.codecId);
if (status)
return status;
- } else if (id == 0x1C) { // lacing
+ } else if (id == libwebm::kMkvFlagLacing) {
lacing = UnserializeUInt(pReader, pos, size);
if ((lacing < 0) || (lacing > 1))
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x23A2) { // Codec Private
+ } else if (id == libwebm::kMkvCodecPrivate) {
delete[] info.codecPrivate;
info.codecPrivate = NULL;
info.codecPrivateSize = 0;
@@ -5502,15 +5759,15 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
info.codecPrivate = buf;
info.codecPrivateSize = buflen;
}
- } else if (id == 0x058688) { // Codec Name
+ } else if (id == libwebm::kMkvCodecName) {
const long status =
UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
if (status)
return status;
- } else if (id == 0x16AA) { // Codec Delay
+ } else if (id == libwebm::kMkvCodecDelay) {
info.codecDelay = UnserializeUInt(pReader, pos, size);
- } else if (id == 0x16BB) { // Seek Pre Roll
+ } else if (id == libwebm::kMkvSeekPreRoll) {
info.seekPreRoll = UnserializeUInt(pReader, pos, size);
}
@@ -5649,97 +5906,87 @@ const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
}
long Cluster::Load(long long& pos, long& len) const {
- assert(m_pSegment);
- assert(m_pos >= m_element_start);
+ if (m_pSegment == NULL)
+ return E_PARSE_FAILED;
if (m_timecode >= 0) // at least partially loaded
return 0;
- assert(m_pos == m_element_start);
- assert(m_element_size < 0);
+ if (m_pos != m_element_start || m_element_size >= 0)
+ return E_PARSE_FAILED;
IMkvReader* const pReader = m_pSegment->m_pReader;
-
long long total, avail;
-
const int status = pReader->Length(&total, &avail);
if (status < 0) // error
return status;
- assert((total < 0) || (avail <= total));
- assert((total < 0) || (m_pos <= total)); // TODO: verify this
+ if (total >= 0 && (avail > total || m_pos > total))
+ return E_FILE_FORMAT_INVALID;
pos = m_pos;
long long cluster_size = -1;
- {
- if ((pos + 1) > avail) {
- len = 1;
- return E_BUFFER_NOT_FULL;
- }
-
- long long result = GetUIntLength(pReader, pos, len);
-
- if (result < 0) // error or underflow
- return static_cast<long>(result);
+ if ((pos + 1) > avail) {
+ len = 1;
+ return E_BUFFER_NOT_FULL;
+ }
- if (result > 0) // underflow (weird)
- return E_BUFFER_NOT_FULL;
+ long long result = GetUIntLength(pReader, pos, len);
- // if ((pos + len) > segment_stop)
- // return E_FILE_FORMAT_INVALID;
+ if (result < 0) // error or underflow
+ return static_cast<long>(result);
- if ((pos + len) > avail)
- return E_BUFFER_NOT_FULL;
+ if (result > 0)
+ return E_BUFFER_NOT_FULL;
- const long long id_ = ReadUInt(pReader, pos, len);
+ if ((pos + len) > avail)
+ return E_BUFFER_NOT_FULL;
- if (id_ < 0) // error
- return static_cast<long>(id_);
+ const long long id_ = ReadID(pReader, pos, len);
- if (id_ != 0x0F43B675) // Cluster ID
- return E_FILE_FORMAT_INVALID;
+ if (id_ < 0) // error
+ return static_cast<long>(id_);
- pos += len; // consume id
+ if (id_ != libwebm::kMkvCluster)
+ return E_FILE_FORMAT_INVALID;
- // read cluster size
+ pos += len; // consume id
- if ((pos + 1) > avail) {
- len = 1;
- return E_BUFFER_NOT_FULL;
- }
+ // read cluster size
- result = GetUIntLength(pReader, pos, len);
+ if ((pos + 1) > avail) {
+ len = 1;
+ return E_BUFFER_NOT_FULL;
+ }
- if (result < 0) // error
- return static_cast<long>(result);
+ result = GetUIntLength(pReader, pos, len);
- if (result > 0) // weird
- return E_BUFFER_NOT_FULL;
+ if (result < 0) // error
+ return static_cast<long>(result);
- // if ((pos + len) > segment_stop)
- // return E_FILE_FORMAT_INVALID;
+ if (result > 0)
+ return E_BUFFER_NOT_FULL;
- if ((pos + len) > avail)
- return E_BUFFER_NOT_FULL;
+ if ((pos + len) > avail)
+ return E_BUFFER_NOT_FULL;
- const long long size = ReadUInt(pReader, pos, len);
+ const long long size = ReadUInt(pReader, pos, len);
- if (size < 0) // error
- return static_cast<long>(cluster_size);
+ if (size < 0) // error
+ return static_cast<long>(cluster_size);
- if (size == 0)
- return E_FILE_FORMAT_INVALID; // TODO: verify this
+ if (size == 0)
+ return E_FILE_FORMAT_INVALID;
- pos += len; // consume length of size of element
+ pos += len; // consume length of size of element
- const long long unknown_size = (1LL << (7 * len)) - 1;
+ const long long unknown_size = (1LL << (7 * len)) - 1;
- if (size != unknown_size)
- cluster_size = size;
- }
+ if (size != unknown_size)
+ cluster_size = size;
// pos points to start of payload
long long timecode = -1;
@@ -5764,7 +6011,7 @@ long Cluster::Load(long long& pos, long& len) const {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
@@ -5773,7 +6020,7 @@ long Cluster::Load(long long& pos, long& len) const {
if ((pos + len) > avail)
return E_BUFFER_NOT_FULL;
- const long long id = ReadUInt(pReader, pos, len);
+ const long long id = ReadID(pReader, pos, len);
if (id < 0) // error
return static_cast<long>(id);
@@ -5785,10 +6032,10 @@ long Cluster::Load(long long& pos, long& len) const {
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == 0x0F43B675) // Cluster ID
+ if (id == libwebm::kMkvCluster)
break;
- if (id == 0x0C53BB6B) // Cues ID
+ if (id == libwebm::kMkvCues)
break;
pos += len; // consume ID field
@@ -5805,7 +6052,7 @@ long Cluster::Load(long long& pos, long& len) const {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
@@ -5831,13 +6078,13 @@ long Cluster::Load(long long& pos, long& len) const {
// pos now points to start of payload
- if (size == 0) // weird
+ if (size == 0)
continue;
if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
return E_FILE_FORMAT_INVALID;
- if (id == 0x67) { // TimeCode ID
+ if (id == libwebm::kMkvTimecode) {
len = static_cast<long>(size);
if ((pos + size) > avail)
@@ -5852,10 +6099,10 @@ long Cluster::Load(long long& pos, long& len) const {
if (bBlock)
break;
- } else if (id == 0x20) { // BlockGroup ID
+ } else if (id == libwebm::kMkvBlockGroup) {
bBlock = true;
break;
- } else if (id == 0x23) { // SimpleBlock ID
+ } else if (id == libwebm::kMkvSimpleBlock) {
bBlock = true;
break;
}
@@ -5889,10 +6136,8 @@ long Cluster::Parse(long long& pos, long& len) const {
if (status < 0)
return status;
- assert(m_pos >= m_element_start);
- assert(m_timecode >= 0);
- // assert(m_size > 0);
- // assert(m_element_size > m_size);
+ if (m_pos < m_element_start || m_timecode < 0)
+ return E_PARSE_FAILED;
const long long cluster_stop =
(m_element_size < 0) ? -1 : m_element_start + m_element_size;
@@ -5909,7 +6154,8 @@ long Cluster::Parse(long long& pos, long& len) const {
if (status < 0) // error
return status;
- assert((total < 0) || (avail <= total));
+ if (total >= 0 && avail > total)
+ return E_FILE_FORMAT_INVALID;
pos = m_pos;
@@ -5936,7 +6182,7 @@ long Cluster::Parse(long long& pos, long& len) const {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
@@ -5945,19 +6191,16 @@ long Cluster::Parse(long long& pos, long& len) const {
if ((pos + len) > avail)
return E_BUFFER_NOT_FULL;
- const long long id = ReadUInt(pReader, pos, len);
-
- if (id < 0) // error
- return static_cast<long>(id);
+ const long long id = ReadID(pReader, pos, len);
- if (id == 0) // weird
+ if (id < 0)
return E_FILE_FORMAT_INVALID;
// This is the distinguished set of ID's we use to determine
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID
+ if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
if (m_element_size < 0)
m_element_size = pos - m_element_start;
@@ -5978,7 +6221,7 @@ long Cluster::Parse(long long& pos, long& len) const {
if (result < 0) // error
return static_cast<long>(result);
- if (result > 0) // weird
+ if (result > 0)
return E_BUFFER_NOT_FULL;
if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
@@ -6004,7 +6247,7 @@ long Cluster::Parse(long long& pos, long& len) const {
// pos now points to start of payload
- if (size == 0) // weird
+ if (size == 0)
continue;
// const long long block_start = pos;
@@ -6012,8 +6255,9 @@ long Cluster::Parse(long long& pos, long& len) const {
if (cluster_stop >= 0) {
if (block_stop > cluster_stop) {
- if ((id == 0x20) || (id == 0x23))
+ if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
return E_FILE_FORMAT_INVALID;
+ }
pos = cluster_stop;
break;
@@ -6029,10 +6273,10 @@ long Cluster::Parse(long long& pos, long& len) const {
Cluster* const this_ = const_cast<Cluster*>(this);
- if (id == 0x20) // BlockGroup
+ if (id == libwebm::kMkvBlockGroup)
return this_->ParseBlockGroup(size, pos, len);
- if (id == 0x23) // SimpleBlock
+ if (id == libwebm::kMkvSimpleBlock)
return this_->ParseSimpleBlock(size, pos, len);
pos += size; // consume payload
@@ -6040,7 +6284,8 @@ long Cluster::Parse(long long& pos, long& len) const {
return E_FILE_FORMAT_INVALID;
}
- assert(m_element_size > 0);
+ if (m_element_size < 1)
+ return E_FILE_FORMAT_INVALID;
m_pos = pos;
if (cluster_stop >= 0 && m_pos > cluster_stop)
@@ -6050,23 +6295,26 @@ long Cluster::Parse(long long& pos, long& len) const {
const long idx = m_entries_count - 1;
const BlockEntry* const pLast = m_entries[idx];
- assert(pLast);
+ if (pLast == NULL)
+ return E_PARSE_FAILED;
const Block* const pBlock = pLast->GetBlock();
- assert(pBlock);
+ if (pBlock == NULL)
+ return E_PARSE_FAILED;
const long long start = pBlock->m_start;
if ((total >= 0) && (start > total))
- return -1; // defend against trucated stream
+ return E_PARSE_FAILED; // defend against trucated stream
const long long size = pBlock->m_size;
const long long stop = start + size;
- assert((cluster_stop < 0) || (stop <= cluster_stop));
+ if (cluster_stop >= 0 && stop > cluster_stop)
+ return E_FILE_FORMAT_INVALID;
if ((total >= 0) && (stop > total))
- return -1; // defend against trucated stream
+ return E_PARSE_FAILED; // defend against trucated stream
}
return 1; // no more entries
@@ -6159,8 +6407,7 @@ long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
return E_BUFFER_NOT_FULL;
}
- status = CreateBlock(0x23, // simple block id
- block_start, block_size,
+ status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
0); // DiscardPadding
if (status != 0)
@@ -6219,12 +6466,12 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
if ((pos + len) > avail)
return E_BUFFER_NOT_FULL;
- const long long id = ReadUInt(pReader, pos, len);
+ const long long id = ReadID(pReader, pos, len);
if (id < 0) // error
return static_cast<long>(id);
- if (id == 0) // not a value ID
+ if (id == 0) // not a valid ID
return E_FILE_FORMAT_INVALID;
pos += len; // consume ID field
@@ -6270,14 +6517,14 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
if (size == unknown_size)
return E_FILE_FORMAT_INVALID;
- if (id == 0x35A2) { // DiscardPadding
+ if (id == libwebm::kMkvDiscardPadding) {
status = UnserializeInt(pReader, pos, size, discard_padding);
if (status < 0) // error
return status;
}
- if (id != 0x21) { // sub-part of BlockGroup is not a Block
+ if (id != libwebm::kMkvBlock) {
pos += size; // consume sub-part of block group
if (pos > payload_stop)
@@ -6370,8 +6617,8 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
if (pos != payload_stop)
return E_FILE_FORMAT_INVALID;
- status = CreateBlock(0x20, // BlockGroup ID
- payload_start, payload_size, discard_padding);
+ status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
+ discard_padding);
if (status != 0)
return status;
@@ -6531,13 +6778,13 @@ long Cluster::HasBlockEntries(
if ((pos + len) > avail)
return E_BUFFER_NOT_FULL;
- const long long id = ReadUInt(pReader, pos, len);
+ const long long id = ReadID(pReader, pos, len);
if (id < 0) // error
return static_cast<long>(id);
- if (id != 0x0F43B675) // weird: not cluster ID
- return -1; // generic error
+ if (id != libwebm::kMkvCluster)
+ return E_PARSE_FAILED;
pos += len; // consume Cluster ID field
@@ -6615,7 +6862,7 @@ long Cluster::HasBlockEntries(
if ((pos + len) > avail)
return E_BUFFER_NOT_FULL;
- const long long id = ReadUInt(pReader, pos, len);
+ const long long id = ReadID(pReader, pos, len);
if (id < 0) // error
return static_cast<long>(id);
@@ -6624,10 +6871,10 @@ long Cluster::HasBlockEntries(
// that we have exhausted the sub-element's inside the cluster
// whose ID we parsed earlier.
- if (id == 0x0F43B675) // Cluster ID
+ if (id == libwebm::kMkvCluster)
return 0; // no entries found
- if (id == 0x0C53BB6B) // Cues ID
+ if (id == libwebm::kMkvCues)
return 0; // no entries found
pos += len; // consume id field
@@ -6679,10 +6926,10 @@ long Cluster::HasBlockEntries(
if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
return E_FILE_FORMAT_INVALID;
- if (id == 0x20) // BlockGroup ID
+ if (id == libwebm::kMkvBlockGroup)
return 1; // have at least one entry
- if (id == 0x23) // SimpleBlock ID
+ if (id == libwebm::kMkvSimpleBlock)
return 1; // have at least one entry
pos += size; // consume payload
@@ -6757,7 +7004,8 @@ long long Cluster::GetLastTime() const {
long Cluster::CreateBlock(long long id,
long long pos, // absolute pos of payload
long long size, long long discard_padding) {
- assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock
+ if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
+ return E_PARSE_FAILED;
if (m_entries_count < 0) { // haven't parsed anything yet
assert(m_entries == NULL);
@@ -6796,9 +7044,9 @@ long Cluster::CreateBlock(long long id,
}
}
- if (id == 0x20) // BlockGroup ID
+ if (id == libwebm::kMkvBlockGroup)
return CreateBlockGroup(pos, size, discard_padding);
- else // SimpleBlock ID
+ else
return CreateSimpleBlock(pos, size);
}
@@ -6841,12 +7089,12 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
pos += len; // consume size
- if (id == 0x21) { // Block ID
+ if (id == libwebm::kMkvBlock) {
if (bpos < 0) { // Block ID
bpos = pos;
bsize = size;
}
- } else if (id == 0x1B) { // Duration ID
+ } else if (id == libwebm::kMkvBlockDuration) {
if (size > 8)
return E_FILE_FORMAT_INVALID;
@@ -6854,7 +7102,7 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
if (duration < 0)
return E_FILE_FORMAT_INVALID;
- } else if (id == 0x7B) { // ReferenceBlock
+ } else if (id == libwebm::kMkvReferenceBlock) {
if (size > 8 || size <= 0)
return E_FILE_FORMAT_INVALID;
const long size_ = static_cast<long>(size);
@@ -6868,7 +7116,7 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
if (time <= 0) // see note above
prev = time;
- else // weird
+ else
next = time;
}
@@ -7201,7 +7449,6 @@ const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
BlockEntry::~BlockEntry() {}
-bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
long BlockEntry::GetIndex() const { return m_index; }
@@ -7525,7 +7772,6 @@ long Block::Parse(const Cluster* pCluster) {
if (pf >= pf_end)
return E_FILE_FORMAT_INVALID;
-
const Frame& prev = *pf++;
assert(prev.len == frame_size);
if (prev.len != frame_size)
@@ -7691,4 +7937,4 @@ long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
long long Block::GetDiscardPadding() const { return m_discard_padding; }
-} // end namespace mkvparser
+} // namespace mkvparser
diff --git a/libwebm/mkvparser.hpp b/libwebm/mkvparser/mkvparser.h
index 75ef69d..42e6e88 100644
--- a/libwebm/mkvparser.hpp
+++ b/libwebm/mkvparser/mkvparser.h
@@ -5,13 +5,10 @@
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
-
-#ifndef MKVPARSER_HPP
-#define MKVPARSER_HPP
+#ifndef MKVPARSER_MKVPARSER_H_
+#define MKVPARSER_MKVPARSER_H_
#include <cstddef>
-#include <cstdio>
-#include <cstdlib>
namespace mkvparser {
@@ -28,8 +25,9 @@ class IMkvReader {
virtual ~IMkvReader();
};
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
- unsigned long long element_size);
+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);
@@ -128,7 +126,7 @@ class BlockEntry {
public:
virtual ~BlockEntry();
- bool EOS() const;
+ bool EOS() const { return (GetKind() == kBlockEOS); }
const Cluster* GetCluster() const;
long GetIndex() const;
virtual const Block* GetBlock() const = 0;
@@ -391,6 +389,90 @@ class Track {
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;
+};
+
class VideoTrack : public Track {
VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
@@ -398,6 +480,7 @@ class VideoTrack : public Track {
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*&);
@@ -412,6 +495,8 @@ class VideoTrack : public Track {
bool VetEntry(const BlockEntry*) const;
long Seek(long long time_ns, const BlockEntry*&) const;
+ Colour* GetColour() const;
+
private:
long long m_width;
long long m_height;
@@ -421,6 +506,8 @@ class VideoTrack : public Track {
long long m_stereo_mode;
double m_rate;
+
+ Colour* m_colour;
};
class AudioTrack : public Track {
@@ -1013,7 +1100,7 @@ class Segment {
const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
};
-} // end namespace mkvparser
+} // namespace mkvparser
inline long mkvparser::Segment::LoadCluster() {
long long pos;
@@ -1022,4 +1109,4 @@ inline long mkvparser::Segment::LoadCluster() {
return LoadCluster(pos, size);
}
-#endif // MKVPARSER_HPP
+#endif // MKVPARSER_MKVPARSER_H_