diff options
author | Vignesh Venkatasubramanian <vigneshv@google.com> | 2016-04-06 11:16:03 -0700 |
---|---|---|
committer | Vignesh Venkatasubramanian <vigneshv@google.com> | 2016-04-13 20:07:21 +0000 |
commit | 38d9709fe466cc2065b6e5ac8f8264beb6bc9efd (patch) | |
tree | 1b43970c3350699bf5366859f5b40a6ebbcb67b1 | |
parent | 94ab74f3a64f07f56e4aa046c96bacf97d0d4614 (diff) | |
download | android_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.mk | 4 | ||||
-rw-r--r-- | libwebm/README.android | 35 | ||||
-rw-r--r-- | libwebm/common/webmids.h | 184 | ||||
-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
@@ -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_ |