Update libwebm
Update of libwebm.
Up-to-date version of libwebm contains several bugfixes that allow playback of files that would crash Godot otherwise.
(cherry picked from commit e71f109910
)
This commit is contained in:
parent
2e9c9f7d74
commit
27f5e404a7
5 changed files with 371 additions and 107 deletions
|
@ -18,6 +18,10 @@ thirdparty_libsimplewebm_sources = [thirdparty_libsimplewebm_dir + file for file
|
|||
env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources)
|
||||
env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"])
|
||||
|
||||
# upstream uses c++11
|
||||
if (not env_webm.msvc):
|
||||
env_webm.Append(CCFLAGS="-std=c++11")
|
||||
|
||||
# also requires libogg, libvorbis and libopus
|
||||
if env['builtin_libogg']:
|
||||
env_webm.Append(CPPPATH=["#thirdparty/libogg"])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
URL: https://chromium.googlesource.com/webm/libwebm
|
||||
Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d
|
||||
Version: d7c62173ff6b4a5e0a2f86683a5b67db98cf09bf
|
||||
License: BSD
|
||||
License File: LICENSE.txt
|
||||
|
||||
|
|
|
@ -124,6 +124,14 @@ enum MkvId {
|
|||
kMkvLuminanceMin = 0x55DA,
|
||||
// end mastering metadata
|
||||
// end colour
|
||||
// projection
|
||||
kMkvProjection = 0x7670,
|
||||
kMkvProjectionType = 0x7671,
|
||||
kMkvProjectionPrivate = 0x7672,
|
||||
kMkvProjectionPoseYaw = 0x7673,
|
||||
kMkvProjectionPosePitch = 0x7674,
|
||||
kMkvProjectionPoseRoll = 0x7675,
|
||||
// end projection
|
||||
// audio
|
||||
kMkvAudio = 0xE1,
|
||||
kMkvSamplingFrequency = 0xB5,
|
||||
|
|
|
@ -12,51 +12,30 @@
|
|||
#define MSC_COMPAT
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
||||
#include "common/webmids.h"
|
||||
|
||||
namespace mkvparser {
|
||||
const long long kStringElementSizeLimit = 20 * 1000 * 1000;
|
||||
const float MasteringMetadata::kValueNotPresent = FLT_MAX;
|
||||
const long long Colour::kValueNotPresent = LLONG_MAX;
|
||||
const float Projection::kValueNotPresent = FLT_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
|
||||
|
||||
template<typename T>
|
||||
class my_auto_ptr {
|
||||
my_auto_ptr(const my_auto_ptr &);
|
||||
T *operator =(const my_auto_ptr &);
|
||||
|
||||
T *m_ptr;
|
||||
public:
|
||||
my_auto_ptr(T *ptr) :
|
||||
m_ptr(ptr)
|
||||
{}
|
||||
my_auto_ptr() :
|
||||
m_ptr(NULL)
|
||||
{}
|
||||
~my_auto_ptr() {
|
||||
delete m_ptr;
|
||||
}
|
||||
|
||||
T *release() {
|
||||
T *ptr = m_ptr;
|
||||
m_ptr = NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T *operator ->() const {
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
IMkvReader::~IMkvReader() {}
|
||||
|
||||
template <typename Type>
|
||||
|
@ -72,7 +51,7 @@ Type* SafeArrayAlloc(unsigned long long num_elements,
|
|||
if (num_bytes != static_cast<size_t>(num_bytes))
|
||||
return NULL;
|
||||
|
||||
return new Type[static_cast<size_t>(num_bytes)];
|
||||
return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
|
||||
}
|
||||
|
||||
void GetVersion(int& major, int& minor, int& build, int& revision) {
|
||||
|
@ -304,7 +283,7 @@ long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
|
|||
result = d;
|
||||
}
|
||||
|
||||
if (isinf(result) || isnan(result))
|
||||
if (mkvparser::isinf(result) || mkvparser::isnan(result))
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
return 0;
|
||||
|
@ -347,7 +326,7 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size,
|
|||
delete[] str;
|
||||
str = NULL;
|
||||
|
||||
if (size >= LONG_MAX || size < 0)
|
||||
if (size >= LONG_MAX || size < 0 || size > kStringElementSizeLimit)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
// +1 for '\0' terminator
|
||||
|
@ -818,7 +797,9 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
|
|||
else if ((pos + size) > total)
|
||||
size = -1;
|
||||
|
||||
pSegment = new Segment(pReader, idpos, pos, size);
|
||||
pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
|
||||
if (pSegment == NULL)
|
||||
return E_PARSE_FAILED;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
@ -954,7 +935,11 @@ long long Segment::ParseHeaders() {
|
|||
if (m_pInfo)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_pInfo = new SegmentInfo(this, pos, size, element_start, element_size);
|
||||
m_pInfo = new (std::nothrow)
|
||||
SegmentInfo(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pInfo == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pInfo->Parse();
|
||||
|
||||
|
@ -964,7 +949,11 @@ long long Segment::ParseHeaders() {
|
|||
if (m_pTracks)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_pTracks = new Tracks(this, pos, size, element_start, element_size);
|
||||
m_pTracks = new (std::nothrow)
|
||||
Tracks(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pTracks == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pTracks->Parse();
|
||||
|
||||
|
@ -972,11 +961,19 @@ long long Segment::ParseHeaders() {
|
|||
return status;
|
||||
} else if (id == libwebm::kMkvCues) {
|
||||
if (m_pCues == NULL) {
|
||||
m_pCues = new Cues(this, pos, size, element_start, element_size);
|
||||
m_pCues = new (std::nothrow)
|
||||
Cues(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pCues == NULL)
|
||||
return -1;
|
||||
}
|
||||
} else if (id == libwebm::kMkvSeekHead) {
|
||||
if (m_pSeekHead == NULL) {
|
||||
m_pSeekHead = new SeekHead(this, pos, size, element_start, element_size);
|
||||
m_pSeekHead = new (std::nothrow)
|
||||
SeekHead(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pSeekHead == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pSeekHead->Parse();
|
||||
|
||||
|
@ -985,7 +982,11 @@ long long Segment::ParseHeaders() {
|
|||
}
|
||||
} else if (id == libwebm::kMkvChapters) {
|
||||
if (m_pChapters == NULL) {
|
||||
m_pChapters = new Chapters(this, pos, size, element_start, element_size);
|
||||
m_pChapters = new (std::nothrow)
|
||||
Chapters(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pChapters == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pChapters->Parse();
|
||||
|
||||
|
@ -994,7 +995,11 @@ long long Segment::ParseHeaders() {
|
|||
}
|
||||
} else if (id == libwebm::kMkvTags) {
|
||||
if (m_pTags == NULL) {
|
||||
m_pTags = new Tags(this, pos, size, element_start, element_size);
|
||||
m_pTags = new (std::nothrow)
|
||||
Tags(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pTags == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pTags->Parse();
|
||||
|
||||
|
@ -1136,7 +1141,9 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
|
|||
if (m_pCues == NULL) {
|
||||
const long long element_size = (pos - idpos) + size;
|
||||
|
||||
m_pCues = new Cues(this, pos, size, idpos, element_size);
|
||||
m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
|
||||
if (m_pCues == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_pos = pos + size; // consume payload
|
||||
|
@ -1342,7 +1349,9 @@ bool Segment::AppendCluster(Cluster* pCluster) {
|
|||
if (count >= size) {
|
||||
const long n = (size <= 0) ? 2048 : 2 * size;
|
||||
|
||||
Cluster** const qq = new Cluster*[n];
|
||||
Cluster** const qq = new (std::nothrow) Cluster*[n];
|
||||
if (qq == NULL)
|
||||
return false;
|
||||
|
||||
Cluster** q = qq;
|
||||
Cluster** p = m_clusters;
|
||||
|
@ -1397,7 +1406,9 @@ bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
|
|||
if (count >= size) {
|
||||
const long n = (size <= 0) ? 2048 : 2 * size;
|
||||
|
||||
Cluster** const qq = new Cluster*[n];
|
||||
Cluster** const qq = new (std::nothrow) Cluster*[n];
|
||||
if (qq == NULL)
|
||||
return false;
|
||||
Cluster** q = qq;
|
||||
|
||||
Cluster** p = m_clusters;
|
||||
|
@ -1466,6 +1477,8 @@ long Segment::Load() {
|
|||
}
|
||||
}
|
||||
|
||||
SeekHead::Entry::Entry() : id(0), pos(0), element_start(0), element_size(0) {}
|
||||
|
||||
SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
|
||||
long long element_start, long long element_size)
|
||||
: m_pSegment(pSegment),
|
||||
|
@ -1516,9 +1529,19 @@ long SeekHead::Parse() {
|
|||
if (pos != stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_entries = new Entry[entry_count];
|
||||
if (entry_count > 0) {
|
||||
m_entries = new (std::nothrow) Entry[entry_count];
|
||||
|
||||
m_void_elements = new VoidElement[void_element_count];
|
||||
if (m_entries == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (void_element_count > 0) {
|
||||
m_void_elements = new (std::nothrow) VoidElement[void_element_count];
|
||||
|
||||
if (m_void_elements == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now parse the entries and void elements
|
||||
|
||||
|
@ -1537,14 +1560,14 @@ long SeekHead::Parse() {
|
|||
if (status < 0) // error
|
||||
return status;
|
||||
|
||||
if (id == libwebm::kMkvSeek) {
|
||||
if (id == libwebm::kMkvSeek && entry_count > 0) {
|
||||
if (ParseEntry(pReader, pos, size, pEntry)) {
|
||||
Entry& e = *pEntry++;
|
||||
|
||||
e.element_start = idpos;
|
||||
e.element_size = (pos + size) - idpos;
|
||||
}
|
||||
} else if (id == libwebm::kMkvVoid) {
|
||||
} else if (id == libwebm::kMkvVoid && void_element_count > 0) {
|
||||
VoidElement& e = *pVoidElement++;
|
||||
|
||||
e.element_start = idpos;
|
||||
|
@ -1706,7 +1729,10 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
|
|||
|
||||
const long long element_size = element_stop - element_start;
|
||||
|
||||
m_pCues = new Cues(this, pos, size, element_start, element_size);
|
||||
m_pCues =
|
||||
new (std::nothrow) Cues(this, pos, size, element_start, element_size);
|
||||
if (m_pCues == NULL)
|
||||
return -1;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
@ -1748,18 +1774,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
|
|||
if ((pos + seekIdSize) > stop)
|
||||
return false;
|
||||
|
||||
// Note that the SeekId payload really is serialized
|
||||
// as a "Matroska integer", not as a plain binary value.
|
||||
// In fact, Matroska requires that ID values in the
|
||||
// stream exactly match the binary representation as listed
|
||||
// in the Matroska specification.
|
||||
//
|
||||
// This parser is more liberal, and permits IDs to have
|
||||
// any width. (This could make the representation in the stream
|
||||
// different from what's in the spec, but it doesn't matter here,
|
||||
// since we always normalize "Matroska integer" values.)
|
||||
|
||||
pEntry->id = ReadUInt(pReader, pos, len); // payload
|
||||
pEntry->id = ReadID(pReader, pos, len); // payload
|
||||
|
||||
if (pEntry->id <= 0)
|
||||
return false;
|
||||
|
@ -1898,7 +1913,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
|
|||
if (m_preload_count >= cue_points_size) {
|
||||
const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
|
||||
|
||||
CuePoint** const qq = new CuePoint*[n];
|
||||
CuePoint** const qq = new (std::nothrow) CuePoint*[n];
|
||||
if (qq == NULL)
|
||||
return false;
|
||||
|
||||
CuePoint** q = qq; // beginning of target
|
||||
|
||||
|
@ -1914,7 +1931,9 @@ bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
|
|||
cue_points_size = n;
|
||||
}
|
||||
|
||||
CuePoint* const pCP = new CuePoint(m_preload_count, pos);
|
||||
CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
|
||||
if (pCP == NULL)
|
||||
return false;
|
||||
|
||||
m_cue_points[m_preload_count++] = pCP;
|
||||
return true;
|
||||
|
@ -2320,7 +2339,9 @@ bool CuePoint::Load(IMkvReader* pReader) {
|
|||
// << " timecode=" << m_timecode
|
||||
// << endl;
|
||||
|
||||
m_track_positions = new TrackPosition[m_track_positions_count];
|
||||
m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
|
||||
if (m_track_positions == NULL)
|
||||
return false;
|
||||
|
||||
// Now parse track positions
|
||||
|
||||
|
@ -2410,7 +2431,9 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
|
|||
}
|
||||
|
||||
const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
|
||||
assert(pTrack);
|
||||
if (pTrack == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const long long n = pTrack->GetNumber();
|
||||
|
||||
|
@ -2915,7 +2938,10 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
|
|||
const long long element_size = element_stop - element_start;
|
||||
|
||||
if (m_pCues == NULL) {
|
||||
m_pCues = new Cues(this, pos, size, element_start, element_size);
|
||||
m_pCues = new (std::nothrow)
|
||||
Cues(this, pos, size, element_start, element_size);
|
||||
if (m_pCues == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
pos += size; // consume payload
|
||||
|
@ -3266,7 +3292,10 @@ bool Chapters::ExpandEditionsArray() {
|
|||
|
||||
const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
|
||||
|
||||
Edition* const editions = new Edition[size];
|
||||
Edition* const editions = new (std::nothrow) Edition[size];
|
||||
|
||||
if (editions == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_editions_count; ++idx) {
|
||||
m_editions[idx].ShallowCopy(editions[idx]);
|
||||
|
@ -3378,7 +3407,10 @@ bool Chapters::Edition::ExpandAtomsArray() {
|
|||
|
||||
const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
|
||||
|
||||
Atom* const atoms = new Atom[size];
|
||||
Atom* const atoms = new (std::nothrow) Atom[size];
|
||||
|
||||
if (atoms == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_atoms_count; ++idx) {
|
||||
m_atoms[idx].ShallowCopy(atoms[idx]);
|
||||
|
@ -3563,7 +3595,10 @@ bool Chapters::Atom::ExpandDisplaysArray() {
|
|||
|
||||
const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
|
||||
|
||||
Display* const displays = new Display[size];
|
||||
Display* const displays = new (std::nothrow) Display[size];
|
||||
|
||||
if (displays == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_displays_count; ++idx) {
|
||||
m_displays[idx].ShallowCopy(displays[idx]);
|
||||
|
@ -3723,7 +3758,10 @@ bool Tags::ExpandTagsArray() {
|
|||
|
||||
const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
|
||||
|
||||
Tag* const tags = new Tag[size];
|
||||
Tag* const tags = new (std::nothrow) Tag[size];
|
||||
|
||||
if (tags == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_tags_count; ++idx) {
|
||||
m_tags[idx].ShallowCopy(tags[idx]);
|
||||
|
@ -3834,7 +3872,10 @@ bool Tags::Tag::ExpandSimpleTagsArray() {
|
|||
|
||||
const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
|
||||
|
||||
SimpleTag* const displays = new SimpleTag[size];
|
||||
SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
|
||||
|
||||
if (displays == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_simple_tags_count; ++idx) {
|
||||
m_simple_tags[idx].ShallowCopy(displays[idx]);
|
||||
|
@ -3992,7 +4033,7 @@ long SegmentInfo::Parse() {
|
|||
}
|
||||
|
||||
const double rollover_check = m_duration * m_timecodeScale;
|
||||
if (rollover_check > LLONG_MAX)
|
||||
if (rollover_check > static_cast<double>(LLONG_MAX))
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if (pos != stop)
|
||||
|
@ -4083,7 +4124,7 @@ ContentEncoding::~ContentEncoding() {
|
|||
}
|
||||
|
||||
const ContentEncoding::ContentCompression*
|
||||
ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
|
||||
ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
|
||||
const ptrdiff_t count = compression_entries_end_ - compression_entries_;
|
||||
assert(count >= 0);
|
||||
|
||||
|
@ -4179,12 +4220,20 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
|||
return -1;
|
||||
|
||||
if (compression_count > 0) {
|
||||
compression_entries_ = new ContentCompression*[compression_count];
|
||||
compression_entries_ =
|
||||
new (std::nothrow) ContentCompression*[compression_count];
|
||||
if (!compression_entries_)
|
||||
return -1;
|
||||
compression_entries_end_ = compression_entries_;
|
||||
}
|
||||
|
||||
if (encryption_count > 0) {
|
||||
encryption_entries_ = new ContentEncryption*[encryption_count];
|
||||
encryption_entries_ =
|
||||
new (std::nothrow) ContentEncryption*[encryption_count];
|
||||
if (!encryption_entries_) {
|
||||
delete[] compression_entries_;
|
||||
return -1;
|
||||
}
|
||||
encryption_entries_end_ = encryption_entries_;
|
||||
}
|
||||
|
||||
|
@ -4204,7 +4253,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
|||
} else if (id == libwebm::kMkvContentEncodingType) {
|
||||
encoding_type_ = UnserializeUInt(pReader, pos, size);
|
||||
} else if (id == libwebm::kMkvContentCompression) {
|
||||
ContentCompression* const compression = new ContentCompression();
|
||||
ContentCompression* const compression =
|
||||
new (std::nothrow) ContentCompression();
|
||||
if (!compression)
|
||||
return -1;
|
||||
|
||||
status = ParseCompressionEntry(pos, size, pReader, compression);
|
||||
if (status) {
|
||||
|
@ -4213,7 +4265,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
|
|||
}
|
||||
*compression_entries_end_++ = compression;
|
||||
} else if (id == libwebm::kMkvContentEncryption) {
|
||||
ContentEncryption* const encryption = new ContentEncryption();
|
||||
ContentEncryption* const encryption =
|
||||
new (std::nothrow) ContentEncryption();
|
||||
if (!encryption)
|
||||
return -1;
|
||||
|
||||
status = ParseEncryptionEntry(pos, size, pReader, encryption);
|
||||
if (status) {
|
||||
|
@ -4419,7 +4474,11 @@ long Track::Create(Segment* pSegment, const Info& info, long long element_start,
|
|||
if (pResult)
|
||||
return -1;
|
||||
|
||||
Track* const pTrack = new Track(pSegment, element_start, element_size);
|
||||
Track* const pTrack =
|
||||
new (std::nothrow) Track(pSegment, element_start, element_size);
|
||||
|
||||
if (pTrack == NULL)
|
||||
return -1; // generic error
|
||||
|
||||
const int status = info.Copy(pTrack->m_info);
|
||||
|
||||
|
@ -4871,7 +4930,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
|
|||
if (count <= 0)
|
||||
return -1;
|
||||
|
||||
content_encoding_entries_ = new ContentEncoding*[count];
|
||||
content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
|
||||
if (!content_encoding_entries_)
|
||||
return -1;
|
||||
|
||||
content_encoding_entries_end_ = content_encoding_entries_;
|
||||
|
||||
pos = start;
|
||||
|
@ -4883,7 +4945,10 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
|
|||
|
||||
// pos now designates start of element
|
||||
if (id == libwebm::kMkvContentEncoding) {
|
||||
ContentEncoding* const content_encoding = new ContentEncoding();
|
||||
ContentEncoding* const content_encoding =
|
||||
new (std::nothrow) ContentEncoding();
|
||||
if (!content_encoding)
|
||||
return -1;
|
||||
|
||||
status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
|
||||
if (status) {
|
||||
|
@ -4917,20 +4982,27 @@ bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
|
|||
if (!reader)
|
||||
return false;
|
||||
|
||||
my_auto_ptr<PrimaryChromaticity> chromaticity_ptr(*chromaticity ? *chromaticity : new PrimaryChromaticity());
|
||||
if (!*chromaticity)
|
||||
*chromaticity = new PrimaryChromaticity();
|
||||
|
||||
float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
|
||||
if (!*chromaticity)
|
||||
return false;
|
||||
|
||||
PrimaryChromaticity* pc = *chromaticity;
|
||||
float* value = is_x ? &pc->x : &pc->y;
|
||||
|
||||
double parser_value = 0;
|
||||
const long long value_parse_status =
|
||||
const long long parse_status =
|
||||
UnserializeFloat(reader, read_pos, value_size, parser_value);
|
||||
|
||||
// Valid range is [0, 1]. Make sure the double is representable as a float
|
||||
// before casting.
|
||||
if (parse_status < 0 || parser_value < 0.0 || parser_value > 1.0 ||
|
||||
(parser_value > 0.0 && parser_value < FLT_MIN))
|
||||
return false;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
|
@ -4939,7 +5011,9 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
|
|||
if (!reader || *mm)
|
||||
return false;
|
||||
|
||||
my_auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
|
||||
std::unique_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;
|
||||
|
@ -4957,6 +5031,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
|
|||
double value = 0;
|
||||
const long long value_parse_status =
|
||||
UnserializeFloat(reader, read_pos, child_size, value);
|
||||
if (value < -FLT_MAX || value > FLT_MAX ||
|
||||
(value > 0.0 && value < FLT_MIN)) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
|
@ -4966,6 +5044,10 @@ bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
|
|||
double value = 0;
|
||||
const long long value_parse_status =
|
||||
UnserializeFloat(reader, read_pos, child_size, value);
|
||||
if (value < -FLT_MAX || value > FLT_MAX ||
|
||||
(value > 0.0 && value < FLT_MIN)) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
|
@ -5018,7 +5100,9 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start,
|
|||
if (!reader || *colour)
|
||||
return false;
|
||||
|
||||
my_auto_ptr<Colour> colour_ptr(new Colour());
|
||||
std::unique_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;
|
||||
|
@ -5109,11 +5193,94 @@ bool Colour::Parse(IMkvReader* reader, long long colour_start,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Projection::Parse(IMkvReader* reader, long long start, long long size,
|
||||
Projection** projection) {
|
||||
if (!reader || *projection)
|
||||
return false;
|
||||
|
||||
std::unique_ptr<Projection> projection_ptr(new Projection());
|
||||
if (!projection_ptr.get())
|
||||
return false;
|
||||
|
||||
const long long end = start + size;
|
||||
long long read_pos = start;
|
||||
|
||||
while (read_pos < end) {
|
||||
long long child_id = 0;
|
||||
long long child_size = 0;
|
||||
|
||||
const long long status =
|
||||
ParseElementHeader(reader, read_pos, end, child_id, child_size);
|
||||
if (status < 0)
|
||||
return false;
|
||||
|
||||
if (child_id == libwebm::kMkvProjectionType) {
|
||||
long long projection_type = kTypeNotPresent;
|
||||
projection_type = UnserializeUInt(reader, read_pos, child_size);
|
||||
if (projection_type < 0)
|
||||
return false;
|
||||
|
||||
projection_ptr->type = static_cast<ProjectionType>(projection_type);
|
||||
} else if (child_id == libwebm::kMkvProjectionPrivate) {
|
||||
unsigned char* data = SafeArrayAlloc<unsigned char>(1, child_size);
|
||||
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
const int status =
|
||||
reader->Read(read_pos, static_cast<long>(child_size), data);
|
||||
|
||||
if (status) {
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
|
||||
projection_ptr->private_data = data;
|
||||
projection_ptr->private_data_length = static_cast<size_t>(child_size);
|
||||
} else {
|
||||
double value = 0;
|
||||
const long long value_parse_status =
|
||||
UnserializeFloat(reader, read_pos, child_size, value);
|
||||
// Make sure value is representable as a float before casting.
|
||||
if (value_parse_status < 0 || value < -FLT_MAX || value > FLT_MAX ||
|
||||
(value > 0.0 && value < FLT_MIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (child_id) {
|
||||
case libwebm::kMkvProjectionPoseYaw:
|
||||
projection_ptr->pose_yaw = static_cast<float>(value);
|
||||
break;
|
||||
case libwebm::kMkvProjectionPosePitch:
|
||||
projection_ptr->pose_pitch = static_cast<float>(value);
|
||||
break;
|
||||
case libwebm::kMkvProjectionPoseRoll:
|
||||
projection_ptr->pose_roll = static_cast<float>(value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
read_pos += child_size;
|
||||
if (read_pos > end)
|
||||
return false;
|
||||
}
|
||||
|
||||
*projection = projection_ptr.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
|
||||
long long element_size)
|
||||
: Track(pSegment, element_start, element_size), m_colour(NULL) {}
|
||||
: Track(pSegment, element_start, element_size),
|
||||
m_colour(NULL),
|
||||
m_projection(NULL) {}
|
||||
|
||||
VideoTrack::~VideoTrack() { delete m_colour; }
|
||||
VideoTrack::~VideoTrack() {
|
||||
delete m_colour;
|
||||
delete m_projection;
|
||||
}
|
||||
|
||||
long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
||||
long long element_start, long long element_size,
|
||||
|
@ -5145,6 +5312,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
|||
const long long stop = pos + s.size;
|
||||
|
||||
Colour* colour = NULL;
|
||||
Projection* projection = NULL;
|
||||
|
||||
while (pos < stop) {
|
||||
long long id, size;
|
||||
|
@ -5195,6 +5363,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
|||
} else if (id == libwebm::kMkvColour) {
|
||||
if (!Colour::Parse(pReader, pos, size, &colour))
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
} else if (id == libwebm::kMkvProjection) {
|
||||
if (!Projection::Parse(pReader, pos, size, &projection))
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
pos += size; // consume payload
|
||||
|
@ -5205,7 +5376,11 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
|||
if (pos != stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
VideoTrack* const pTrack = new VideoTrack(pSegment, element_start, element_size);
|
||||
VideoTrack* const pTrack =
|
||||
new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
|
||||
|
||||
if (pTrack == NULL)
|
||||
return -1; // generic error
|
||||
|
||||
const int status = info.Copy(pTrack->m_info);
|
||||
|
||||
|
@ -5222,6 +5397,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
|
|||
pTrack->m_stereo_mode = stereo_mode;
|
||||
pTrack->m_rate = rate;
|
||||
pTrack->m_colour = colour;
|
||||
pTrack->m_projection = projection;
|
||||
|
||||
pResult = pTrack;
|
||||
return 0; // success
|
||||
|
@ -5322,6 +5498,8 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
|
|||
|
||||
Colour* VideoTrack::GetColour() const { return m_colour; }
|
||||
|
||||
Projection* VideoTrack::GetProjection() const { return m_projection; }
|
||||
|
||||
long long VideoTrack::GetWidth() const { return m_width; }
|
||||
|
||||
long long VideoTrack::GetHeight() const { return m_height; }
|
||||
|
@ -5404,7 +5582,11 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
|
|||
if (pos != stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
AudioTrack* const pTrack = new AudioTrack(pSegment, element_start, element_size);
|
||||
AudioTrack* const pTrack =
|
||||
new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
|
||||
|
||||
if (pTrack == NULL)
|
||||
return -1; // generic error
|
||||
|
||||
const int status = info.Copy(pTrack->m_info);
|
||||
|
||||
|
@ -5472,7 +5654,11 @@ long Tracks::Parse() {
|
|||
if (count <= 0)
|
||||
return 0; // success
|
||||
|
||||
m_trackEntries = new Track*[count];
|
||||
m_trackEntries = new (std::nothrow) Track*[count];
|
||||
|
||||
if (m_trackEntries == NULL)
|
||||
return -1;
|
||||
|
||||
m_trackEntriesEnd = m_trackEntries;
|
||||
|
||||
pos = m_start;
|
||||
|
@ -6575,7 +6761,10 @@ Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
|
|||
|
||||
const long long element_start = pSegment->m_start + off;
|
||||
|
||||
return new Cluster(pSegment, idx, element_start);
|
||||
Cluster* const pCluster =
|
||||
new (std::nothrow) Cluster(pSegment, idx, element_start);
|
||||
|
||||
return pCluster;
|
||||
}
|
||||
|
||||
Cluster::Cluster()
|
||||
|
@ -6604,8 +6793,10 @@ Cluster::Cluster(Segment* pSegment, long idx, long long element_start
|
|||
{}
|
||||
|
||||
Cluster::~Cluster() {
|
||||
if (m_entries_count <= 0)
|
||||
if (m_entries_count <= 0) {
|
||||
delete[] m_entries;
|
||||
return;
|
||||
}
|
||||
|
||||
BlockEntry** i = m_entries;
|
||||
BlockEntry** const j = m_entries + m_entries_count;
|
||||
|
@ -6918,7 +7109,9 @@ long Cluster::CreateBlock(long long id,
|
|||
assert(m_entries_size == 0);
|
||||
|
||||
m_entries_size = 1024;
|
||||
m_entries = new BlockEntry*[m_entries_size];
|
||||
m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
|
||||
if (m_entries == NULL)
|
||||
return -1;
|
||||
|
||||
m_entries_count = 0;
|
||||
} else {
|
||||
|
@ -6929,7 +7122,9 @@ long Cluster::CreateBlock(long long id,
|
|||
if (m_entries_count >= m_entries_size) {
|
||||
const long entries_size = 2 * m_entries_size;
|
||||
|
||||
BlockEntry** const entries = new BlockEntry*[entries_size];
|
||||
BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
|
||||
if (entries == NULL)
|
||||
return -1;
|
||||
|
||||
BlockEntry** src = m_entries;
|
||||
BlockEntry** const src_end = src + m_entries_count;
|
||||
|
@ -7038,7 +7233,11 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
|
|||
BlockEntry** const ppEntry = m_entries + idx;
|
||||
BlockEntry*& pEntry = *ppEntry;
|
||||
|
||||
pEntry = new BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
|
||||
pEntry = new (std::nothrow)
|
||||
BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
|
||||
|
||||
if (pEntry == NULL)
|
||||
return -1; // generic error
|
||||
|
||||
BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
|
||||
|
||||
|
@ -7066,7 +7265,10 @@ long Cluster::CreateSimpleBlock(long long st, long long sz) {
|
|||
BlockEntry** const ppEntry = m_entries + idx;
|
||||
BlockEntry*& pEntry = *ppEntry;
|
||||
|
||||
pEntry = new SimpleBlock(this, idx, st, sz);
|
||||
pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
|
||||
|
||||
if (pEntry == NULL)
|
||||
return -1; // generic error
|
||||
|
||||
SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
|
||||
|
||||
|
@ -7461,7 +7663,9 @@ long Block::Parse(const Cluster* pCluster) {
|
|||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_frame_count = 1;
|
||||
m_frames = new Frame[m_frame_count];
|
||||
m_frames = new (std::nothrow) Frame[m_frame_count];
|
||||
if (m_frames == NULL)
|
||||
return -1;
|
||||
|
||||
Frame& f = m_frames[0];
|
||||
f.pos = pos;
|
||||
|
@ -7492,7 +7696,9 @@ long Block::Parse(const Cluster* pCluster) {
|
|||
|
||||
m_frame_count = int(biased_count) + 1;
|
||||
|
||||
m_frames = new Frame[m_frame_count];
|
||||
m_frames = new (std::nothrow) Frame[m_frame_count];
|
||||
if (m_frames == NULL)
|
||||
return -1;
|
||||
|
||||
if (!m_frames)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
@ -7701,6 +7907,10 @@ long Block::Parse(const Cluster* pCluster) {
|
|||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
curr.len = static_cast<long>(frame_size);
|
||||
// Check if size + curr.len could overflow.
|
||||
if (size > LLONG_MAX - curr.len) {
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
}
|
||||
size += curr.len; // contribution of this frame
|
||||
|
||||
--frame_count;
|
||||
|
@ -7741,7 +7951,6 @@ long Block::Parse(const Cluster* pCluster) {
|
|||
pf = m_frames;
|
||||
while (pf != pf_end) {
|
||||
Frame& f = *pf++;
|
||||
assert((pos + f.len) <= stop);
|
||||
if ((pos + f.len) > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
|
@ -7763,6 +7972,11 @@ long long Block::GetTimeCode(const Cluster* pCluster) const {
|
|||
const long long tc0 = pCluster->GetTimeCode();
|
||||
assert(tc0 >= 0);
|
||||
|
||||
// Check if tc0 + m_timecode would overflow.
|
||||
if (tc0 < 0 || LLONG_MAX - tc0 < m_timecode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const long long tc = tc0 + m_timecode;
|
||||
|
||||
return tc; // unscaled timecode units
|
||||
|
@ -7780,6 +7994,10 @@ long long Block::GetTime(const Cluster* pCluster) const {
|
|||
const long long scale = pInfo->GetTimeCodeScale();
|
||||
assert(scale >= 1);
|
||||
|
||||
// Check if tc * scale could overflow.
|
||||
if (tc != 0 && scale > LLONG_MAX / tc) {
|
||||
return -1;
|
||||
}
|
||||
const long long ns = tc * scale;
|
||||
|
||||
return ns;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#ifndef MKVPARSER_MKVPARSER_H_
|
||||
#define MKVPARSER_MKVPARSER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mkvparser {
|
||||
|
||||
|
@ -21,6 +21,7 @@ class IMkvReader {
|
|||
virtual int Read(long long pos, long len, unsigned char* buf) = 0;
|
||||
virtual int Length(long long* total, long long* available) = 0;
|
||||
|
||||
public:
|
||||
virtual ~IMkvReader();
|
||||
};
|
||||
|
||||
|
@ -472,6 +473,34 @@ struct Colour {
|
|||
MasteringMetadata* mastering_metadata;
|
||||
};
|
||||
|
||||
struct Projection {
|
||||
enum ProjectionType {
|
||||
kTypeNotPresent = -1,
|
||||
kRectangular = 0,
|
||||
kEquirectangular = 1,
|
||||
kCubeMap = 2,
|
||||
kMesh = 3,
|
||||
};
|
||||
static const float kValueNotPresent;
|
||||
Projection()
|
||||
: type(kTypeNotPresent),
|
||||
private_data(NULL),
|
||||
private_data_length(0),
|
||||
pose_yaw(kValueNotPresent),
|
||||
pose_pitch(kValueNotPresent),
|
||||
pose_roll(kValueNotPresent) {}
|
||||
~Projection() { delete[] private_data; }
|
||||
static bool Parse(IMkvReader* reader, long long element_start,
|
||||
long long element_size, Projection** projection);
|
||||
|
||||
ProjectionType type;
|
||||
unsigned char* private_data;
|
||||
size_t private_data_length;
|
||||
float pose_yaw;
|
||||
float pose_pitch;
|
||||
float pose_roll;
|
||||
};
|
||||
|
||||
class VideoTrack : public Track {
|
||||
VideoTrack(const VideoTrack&);
|
||||
VideoTrack& operator=(const VideoTrack&);
|
||||
|
@ -496,6 +525,8 @@ class VideoTrack : public Track {
|
|||
|
||||
Colour* GetColour() const;
|
||||
|
||||
Projection* GetProjection() const;
|
||||
|
||||
private:
|
||||
long long m_width;
|
||||
long long m_height;
|
||||
|
@ -507,6 +538,7 @@ class VideoTrack : public Track {
|
|||
double m_rate;
|
||||
|
||||
Colour* m_colour;
|
||||
Projection* m_projection;
|
||||
};
|
||||
|
||||
class AudioTrack : public Track {
|
||||
|
@ -812,6 +844,8 @@ class SeekHead {
|
|||
long Parse();
|
||||
|
||||
struct Entry {
|
||||
Entry();
|
||||
|
||||
// the SeekHead entry payload
|
||||
long long id;
|
||||
long long pos;
|
||||
|
|
Loading…
Reference in a new issue