diff options
-rw-r--r-- | third_party/libwebm/README.libvpx | 2 | ||||
-rw-r--r-- | third_party/libwebm/common/file_util.cc | 17 | ||||
-rw-r--r-- | third_party/libwebm/common/hdr_util.cc | 168 | ||||
-rw-r--r-- | third_party/libwebm/common/hdr_util.h | 24 | ||||
-rw-r--r-- | third_party/libwebm/common/webmids.h | 8 | ||||
-rw-r--r-- | third_party/libwebm/mkvmuxer/mkvmuxer.cc | 819 | ||||
-rw-r--r-- | third_party/libwebm/mkvmuxer/mkvmuxer.h | 304 | ||||
-rw-r--r-- | third_party/libwebm/mkvmuxer/mkvmuxerutil.cc | 325 | ||||
-rw-r--r-- | third_party/libwebm/mkvmuxer/mkvmuxerutil.h | 85 | ||||
-rw-r--r-- | third_party/libwebm/mkvmuxer/mkvwriter.cc | 2 | ||||
-rw-r--r-- | third_party/libwebm/mkvparser/mkvparser.cc | 114 | ||||
-rw-r--r-- | third_party/libwebm/mkvparser/mkvparser.h | 33 | ||||
-rw-r--r-- | third_party/libwebm/mkvparser/mkvreader.cc | 4 |
13 files changed, 1414 insertions, 491 deletions
diff --git a/third_party/libwebm/README.libvpx b/third_party/libwebm/README.libvpx index 73f830322..1f8a13d78 100644 --- a/third_party/libwebm/README.libvpx +++ b/third_party/libwebm/README.libvpx @@ -1,5 +1,5 @@ URL: https://chromium.googlesource.com/webm/libwebm -Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d +Version: 9732ae991efb71aced4267d4794918279e362d99 License: BSD License File: LICENSE.txt diff --git a/third_party/libwebm/common/file_util.cc b/third_party/libwebm/common/file_util.cc index 4f91318f3..6dab146dd 100644 --- a/third_party/libwebm/common/file_util.cc +++ b/third_party/libwebm/common/file_util.cc @@ -14,6 +14,7 @@ #include <cstdio> #include <cstdlib> +#include <cstring> #include <fstream> #include <ios> @@ -21,13 +22,23 @@ namespace libwebm { std::string GetTempFileName() { #if !defined _MSC_VER && !defined __MINGW32__ - char temp_file_name_template[] = "libwebm_temp.XXXXXX"; + std::string temp_file_name_template_str = + std::string(std::getenv("TEST_TMPDIR") ? std::getenv("TEST_TMPDIR") : + ".") + + "/libwebm_temp.XXXXXX"; + char* temp_file_name_template = + new char[temp_file_name_template_str.length() + 1]; + memset(temp_file_name_template, 0, temp_file_name_template_str.length() + 1); + temp_file_name_template_str.copy(temp_file_name_template, + temp_file_name_template_str.length(), 0); int fd = mkstemp(temp_file_name_template); + std::string temp_file_name = + (fd != -1) ? std::string(temp_file_name_template) : std::string(); + delete[] temp_file_name_template; if (fd != -1) { close(fd); - return std::string(temp_file_name_template); } - return std::string(); + return temp_file_name; #else char tmp_file_name[_MAX_PATH]; errno_t err = tmpnam_s(tmp_file_name); diff --git a/third_party/libwebm/common/hdr_util.cc b/third_party/libwebm/common/hdr_util.cc index e1a9842fb..e1618ce75 100644 --- a/third_party/libwebm/common/hdr_util.cc +++ b/third_party/libwebm/common/hdr_util.cc @@ -7,12 +7,15 @@ // be found in the AUTHORS file in the root of the source tree. #include "hdr_util.h" +#include <climits> #include <cstddef> #include <new> #include "mkvparser/mkvparser.h" namespace libwebm { +const int Vp9CodecFeatures::kValueNotPresent = INT_MAX; + bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc, PrimaryChromaticityPtr* muxer_pc) { muxer_pc->reset(new (std::nothrow) @@ -29,9 +32,9 @@ bool MasteringMetadataValuePresent(double value) { bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm, mkvmuxer::MasteringMetadata* muxer_mm) { if (MasteringMetadataValuePresent(parser_mm.luminance_max)) - muxer_mm->luminance_max = parser_mm.luminance_max; + muxer_mm->set_luminance_max(parser_mm.luminance_max); if (MasteringMetadataValuePresent(parser_mm.luminance_min)) - muxer_mm->luminance_min = parser_mm.luminance_min; + muxer_mm->set_luminance_min(parser_mm.luminance_min); PrimaryChromaticityPtr r_ptr(NULL); PrimaryChromaticityPtr g_ptr(NULL); @@ -73,34 +76,37 @@ bool CopyColour(const mkvparser::Colour& parser_colour, return false; if (ColourValuePresent(parser_colour.matrix_coefficients)) - muxer_colour->matrix_coefficients = parser_colour.matrix_coefficients; + muxer_colour->set_matrix_coefficients(parser_colour.matrix_coefficients); if (ColourValuePresent(parser_colour.bits_per_channel)) - muxer_colour->bits_per_channel = parser_colour.bits_per_channel; - if (ColourValuePresent(parser_colour.chroma_subsampling_horz)) - muxer_colour->chroma_subsampling_horz = - parser_colour.chroma_subsampling_horz; - if (ColourValuePresent(parser_colour.chroma_subsampling_vert)) - muxer_colour->chroma_subsampling_vert = - parser_colour.chroma_subsampling_vert; + muxer_colour->set_bits_per_channel(parser_colour.bits_per_channel); + if (ColourValuePresent(parser_colour.chroma_subsampling_horz)) { + muxer_colour->set_chroma_subsampling_horz( + parser_colour.chroma_subsampling_horz); + } + if (ColourValuePresent(parser_colour.chroma_subsampling_vert)) { + muxer_colour->set_chroma_subsampling_vert( + parser_colour.chroma_subsampling_vert); + } if (ColourValuePresent(parser_colour.cb_subsampling_horz)) - muxer_colour->cb_subsampling_horz = parser_colour.cb_subsampling_horz; + muxer_colour->set_cb_subsampling_horz(parser_colour.cb_subsampling_horz); if (ColourValuePresent(parser_colour.cb_subsampling_vert)) - muxer_colour->cb_subsampling_vert = parser_colour.cb_subsampling_vert; + muxer_colour->set_cb_subsampling_vert(parser_colour.cb_subsampling_vert); if (ColourValuePresent(parser_colour.chroma_siting_horz)) - muxer_colour->chroma_siting_horz = parser_colour.chroma_siting_horz; + muxer_colour->set_chroma_siting_horz(parser_colour.chroma_siting_horz); if (ColourValuePresent(parser_colour.chroma_siting_vert)) - muxer_colour->chroma_siting_vert = parser_colour.chroma_siting_vert; + muxer_colour->set_chroma_siting_vert(parser_colour.chroma_siting_vert); if (ColourValuePresent(parser_colour.range)) - muxer_colour->range = parser_colour.range; - if (ColourValuePresent(parser_colour.transfer_characteristics)) - muxer_colour->transfer_characteristics = - parser_colour.transfer_characteristics; + muxer_colour->set_range(parser_colour.range); + if (ColourValuePresent(parser_colour.transfer_characteristics)) { + muxer_colour->set_transfer_characteristics( + parser_colour.transfer_characteristics); + } if (ColourValuePresent(parser_colour.primaries)) - muxer_colour->primaries = parser_colour.primaries; + muxer_colour->set_primaries(parser_colour.primaries); if (ColourValuePresent(parser_colour.max_cll)) - muxer_colour->max_cll = parser_colour.max_cll; + muxer_colour->set_max_cll(parser_colour.max_cll); if (ColourValuePresent(parser_colour.max_fall)) - muxer_colour->max_fall = parser_colour.max_fall; + muxer_colour->set_max_fall(parser_colour.max_fall); if (parser_colour.mastering_metadata) { mkvmuxer::MasteringMetadata muxer_mm; @@ -116,8 +122,8 @@ bool CopyColour(const mkvparser::Colour& parser_colour, // // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | ID Byte | Length | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | +// | ID Byte | Length | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | // | | // : Bytes 1..Length of Codec Feature : // | | @@ -132,51 +138,83 @@ bool CopyColour(const mkvparser::Colour& parser_colour, // // The X bit is reserved. // -// Currently only profile level is supported. ID byte must be set to 1, and -// length must be 1. Supported values are: -// -// 10: Level 1 -// 11: Level 1.1 -// 20: Level 2 -// 21: Level 2.1 -// 30: Level 3 -// 31: Level 3.1 -// 40: Level 4 -// 41: Level 4.1 -// 50: Level 5 -// 51: Level 5.1 -// 52: Level 5.2 -// 60: Level 6 -// 61: Level 6.1 -// 62: Level 6.2 -// // See the following link for more information: // http://www.webmproject.org/vp9/profiles/ -int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length) { - const int kVpxCodecPrivateLength = 3; - if (!private_data || length != kVpxCodecPrivateLength) - return 0; - - const uint8_t id_byte = *private_data; - if (id_byte != 1) - return 0; - - const int kVpxProfileLength = 1; - const uint8_t length_byte = private_data[1]; - if (length_byte != kVpxProfileLength) - return 0; - - const int level = static_cast<int>(private_data[2]); - - const int kNumLevels = 14; - const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40, - 41, 50, 51, 52, 60, 61, 62}; +bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length, + Vp9CodecFeatures* features) { + const int kVpxCodecPrivateMinLength = 3; + if (!private_data || !features || length < kVpxCodecPrivateMinLength) + return false; - for (int i = 0; i < kNumLevels; ++i) { - if (level == levels[i]) - return level; - } + const uint8_t kVp9ProfileId = 1; + const uint8_t kVp9LevelId = 2; + const uint8_t kVp9BitDepthId = 3; + const uint8_t kVp9ChromaSubsamplingId = 4; + const int kVpxFeatureLength = 1; + int offset = 0; + + // Set features to not set. + features->profile = Vp9CodecFeatures::kValueNotPresent; + features->level = Vp9CodecFeatures::kValueNotPresent; + features->bit_depth = Vp9CodecFeatures::kValueNotPresent; + features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent; + do { + const uint8_t id_byte = private_data[offset++]; + const uint8_t length_byte = private_data[offset++]; + if (length_byte != kVpxFeatureLength) + return false; + if (id_byte == kVp9ProfileId) { + const int priv_profile = static_cast<int>(private_data[offset++]); + if (priv_profile < 0 || priv_profile > 3) + return false; + if (features->profile != Vp9CodecFeatures::kValueNotPresent && + features->profile != priv_profile) { + return false; + } + features->profile = priv_profile; + } else if (id_byte == kVp9LevelId) { + const int priv_level = static_cast<int>(private_data[offset++]); + + const int kNumLevels = 14; + const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40, + 41, 50, 51, 52, 60, 61, 62}; + + for (int i = 0; i < kNumLevels; ++i) { + if (priv_level == levels[i]) { + if (features->level != Vp9CodecFeatures::kValueNotPresent && + features->level != priv_level) { + return false; + } + features->level = priv_level; + break; + } + } + if (features->level == Vp9CodecFeatures::kValueNotPresent) + return false; + } else if (id_byte == kVp9BitDepthId) { + const int priv_profile = static_cast<int>(private_data[offset++]); + if (priv_profile != 8 && priv_profile != 10 && priv_profile != 12) + return false; + if (features->bit_depth != Vp9CodecFeatures::kValueNotPresent && + features->bit_depth != priv_profile) { + return false; + } + features->bit_depth = priv_profile; + } else if (id_byte == kVp9ChromaSubsamplingId) { + const int priv_profile = static_cast<int>(private_data[offset++]); + if (priv_profile != 0 && priv_profile != 2 && priv_profile != 3) + return false; + if (features->chroma_subsampling != Vp9CodecFeatures::kValueNotPresent && + features->chroma_subsampling != priv_profile) { + return false; + } + features->chroma_subsampling = priv_profile; + } else { + // Invalid ID. + return false; + } + } while (offset + kVpxCodecPrivateMinLength <= length); - return 0; + return true; } } // namespace libwebm diff --git a/third_party/libwebm/common/hdr_util.h b/third_party/libwebm/common/hdr_util.h index d30c2b9f2..689fb30a3 100644 --- a/third_party/libwebm/common/hdr_util.h +++ b/third_party/libwebm/common/hdr_util.h @@ -28,6 +28,25 @@ namespace libwebm { // TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is // required by libwebm. +// Features of the VP9 codec that may be set in the CodecPrivate of a VP9 video +// stream. A value of kValueNotPresent represents that the value was not set in +// the CodecPrivate. +struct Vp9CodecFeatures { + static const int kValueNotPresent; + + Vp9CodecFeatures() + : profile(kValueNotPresent), + level(kValueNotPresent), + bit_depth(kValueNotPresent), + chroma_subsampling(kValueNotPresent) {} + ~Vp9CodecFeatures() {} + + int profile; + int level; + int bit_depth; + int chroma_subsampling; +}; + typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr; bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc, @@ -43,8 +62,9 @@ bool ColourValuePresent(long long value); bool CopyColour(const mkvparser::Colour& parser_colour, mkvmuxer::Colour* muxer_colour); -// Returns VP9 profile upon success or 0 upon failure. -int ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length); +// Returns true if |features| is set to one or more valid values. +bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length, + Vp9CodecFeatures* features); } // namespace libwebm diff --git a/third_party/libwebm/common/webmids.h b/third_party/libwebm/common/webmids.h index 32a0c5fb9..89d722a71 100644 --- a/third_party/libwebm/common/webmids.h +++ b/third_party/libwebm/common/webmids.h @@ -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, diff --git a/third_party/libwebm/mkvmuxer/mkvmuxer.cc b/third_party/libwebm/mkvmuxer/mkvmuxer.cc index c79ce24ed..299b45c98 100644 --- a/third_party/libwebm/mkvmuxer/mkvmuxer.cc +++ b/third_party/libwebm/mkvmuxer/mkvmuxer.cc @@ -16,6 +16,7 @@ #include <ctime> #include <memory> #include <new> +#include <string> #include <vector> #include "common/webmids.h" @@ -25,10 +26,19 @@ namespace mkvmuxer { +const float PrimaryChromaticity::kChromaticityMin = 0.0f; +const float PrimaryChromaticity::kChromaticityMax = 1.0f; +const float MasteringMetadata::kMinLuminance = 0.0f; +const float MasteringMetadata::kMinLuminanceMax = 999.99f; +const float MasteringMetadata::kMaxLuminanceMax = 9999.99f; const float MasteringMetadata::kValueNotPresent = FLT_MAX; const uint64_t Colour::kValueNotPresent = UINT64_MAX; namespace { + +const char kDocTypeWebm[] = "webm"; +const char kDocTypeMatroska[] = "matroska"; + // Deallocate the string designated by |dst|, and then copy the |src| // string to |dst|. The caller owns both the |src| string and the // |dst| copy (hence the caller is responsible for eventually @@ -63,7 +73,7 @@ bool CopyChromaticity(const PrimaryChromaticity* src, if (!dst) return false; - dst->reset(new (std::nothrow) PrimaryChromaticity(src->x, src->y)); + dst->reset(new (std::nothrow) PrimaryChromaticity(src->x(), src->y())); if (!dst->get()) return false; @@ -80,36 +90,57 @@ IMkvWriter::IMkvWriter() {} IMkvWriter::~IMkvWriter() {} -bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) { +bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version, + const char* const doc_type) { // Level 0 - uint64_t size = EbmlElementSize(libwebm::kMkvEBMLVersion, UINT64_C(1)); - size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, UINT64_C(1)); - size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, UINT64_C(4)); - size += EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8)); - size += EbmlElementSize(libwebm::kMkvDocType, "webm"); - size += EbmlElementSize(libwebm::kMkvDocTypeVersion, doc_type_version); - size += EbmlElementSize(libwebm::kMkvDocTypeReadVersion, UINT64_C(2)); + uint64_t size = + EbmlElementSize(libwebm::kMkvEBMLVersion, static_cast<uint64>(1)); + size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, static_cast<uint64>(1)); + size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, static_cast<uint64>(4)); + size += + EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, static_cast<uint64>(8)); + size += EbmlElementSize(libwebm::kMkvDocType, doc_type); + size += EbmlElementSize(libwebm::kMkvDocTypeVersion, + static_cast<uint64>(doc_type_version)); + size += + EbmlElementSize(libwebm::kMkvDocTypeReadVersion, static_cast<uint64>(2)); if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size)) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion, UINT64_C(1))) + if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion, + static_cast<uint64>(1))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion, UINT64_C(1))) + } + if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion, + static_cast<uint64>(1))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength, UINT64_C(4))) + } + if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength, + static_cast<uint64>(4))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8))) + } + if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength, + static_cast<uint64>(8))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvDocType, "webm")) + } + if (!WriteEbmlElement(writer, libwebm::kMkvDocType, doc_type)) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion, doc_type_version)) + if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion, + static_cast<uint64>(doc_type_version))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion, UINT64_C(2))) + } + if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion, + static_cast<uint64>(2))) { return false; + } return true; } +bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) { + return WriteEbmlHeader(writer, doc_type_version, kDocTypeWebm); +} + bool WriteEbmlHeader(IMkvWriter* writer) { return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion); } @@ -262,15 +293,17 @@ bool CuePoint::Write(IMkvWriter* writer) const { if (!writer || track_ < 1 || cluster_pos_ < 1) return false; - uint64_t size = - EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_); - size += EbmlElementSize(libwebm::kMkvCueTrack, track_); + uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition, + static_cast<uint64>(cluster_pos_)); + size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_)); if (output_block_number_ && block_number_ > 1) - size += EbmlElementSize(libwebm::kMkvCueBlockNumber, block_number_); + size += EbmlElementSize(libwebm::kMkvCueBlockNumber, + static_cast<uint64>(block_number_)); const uint64_t track_pos_size = EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size; const uint64_t payload_size = - EbmlElementSize(libwebm::kMkvCueTime, time_) + track_pos_size; + EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) + + track_pos_size; if (!WriteEbmlMasterElement(writer, libwebm::kMkvCuePoint, payload_size)) return false; @@ -279,18 +312,27 @@ bool CuePoint::Write(IMkvWriter* writer) const { if (payload_position < 0) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvCueTime, time_)) + if (!WriteEbmlElement(writer, libwebm::kMkvCueTime, + static_cast<uint64>(time_))) { return false; + } if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size)) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack, track_)) + if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack, + static_cast<uint64>(track_))) { return false; - if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition, cluster_pos_)) + } + if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition, + static_cast<uint64>(cluster_pos_))) { return false; - if (output_block_number_ && block_number_ > 1) - if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber, block_number_)) + } + if (output_block_number_ && block_number_ > 1) { + if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber, + static_cast<uint64>(block_number_))) { return false; + } + } const int64_t stop_position = writer->Position(); if (stop_position < 0) @@ -303,15 +345,17 @@ bool CuePoint::Write(IMkvWriter* writer) const { } uint64_t CuePoint::PayloadSize() const { - uint64_t size = - EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_); - size += EbmlElementSize(libwebm::kMkvCueTrack, track_); + uint64_t size = EbmlElementSize(libwebm::kMkvCueClusterPosition, + static_cast<uint64>(cluster_pos_)); + size += EbmlElementSize(libwebm::kMkvCueTrack, static_cast<uint64>(track_)); if (output_block_number_ && block_number_ > 1) - size += EbmlElementSize(libwebm::kMkvCueBlockNumber, block_number_); + size += EbmlElementSize(libwebm::kMkvCueBlockNumber, + static_cast<uint64>(block_number_)); const uint64_t track_pos_size = EbmlMasterElementSize(libwebm::kMkvCueTrackPositions, size) + size; const uint64_t payload_size = - EbmlElementSize(libwebm::kMkvCueTime, time_) + track_pos_size; + EbmlElementSize(libwebm::kMkvCueTime, static_cast<uint64>(time_)) + + track_pos_size; return payload_size; } @@ -456,8 +500,9 @@ bool ContentEncAESSettings::Write(IMkvWriter* writer) const { return false; if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode, - cipher_mode_)) + static_cast<uint64>(cipher_mode_))) { return false; + } const int64_t stop_position = writer->Position(); if (stop_position < 0 || @@ -468,8 +513,8 @@ bool ContentEncAESSettings::Write(IMkvWriter* writer) const { } uint64_t ContentEncAESSettings::PayloadSize() const { - uint64_t size = - EbmlElementSize(libwebm::kMkvAESSettingsCipherMode, cipher_mode_); + uint64_t size = EbmlElementSize(libwebm::kMkvAESSettingsCipherMode, + static_cast<uint64>(cipher_mode_)); return size; } @@ -529,20 +574,22 @@ bool ContentEncoding::Write(IMkvWriter* writer) const { encoding_size)) return false; if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder, - encoding_order_)) + static_cast<uint64>(encoding_order_))) return false; if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope, - encoding_scope_)) + static_cast<uint64>(encoding_scope_))) return false; if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType, - encoding_type_)) + static_cast<uint64>(encoding_type_))) return false; if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption, encryption_size)) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo, enc_algo_)) + if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo, + static_cast<uint64>(enc_algo_))) { return false; + } if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_)) return false; @@ -571,12 +618,12 @@ uint64_t ContentEncoding::EncodingSize(uint64_t compresion_size, EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) + encryption_size; } - encoding_size += - EbmlElementSize(libwebm::kMkvContentEncodingType, encoding_type_); - encoding_size += - EbmlElementSize(libwebm::kMkvContentEncodingScope, encoding_scope_); - encoding_size += - EbmlElementSize(libwebm::kMkvContentEncodingOrder, encoding_order_); + encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingType, + static_cast<uint64>(encoding_type_)); + encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingScope, + static_cast<uint64>(encoding_scope_)); + encoding_size += EbmlElementSize(libwebm::kMkvContentEncodingOrder, + static_cast<uint64>(encoding_order_)); return encoding_size; } @@ -586,7 +633,8 @@ uint64_t ContentEncoding::EncryptionSize() const { uint64_t encryption_size = EbmlElementSize(libwebm::kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_); - encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo, enc_algo_); + encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo, + static_cast<uint64>(enc_algo_)); return encryption_size + aes_size; } @@ -664,9 +712,10 @@ ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const { } uint64_t Track::PayloadSize() const { - uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_); - size += EbmlElementSize(libwebm::kMkvTrackUID, uid_); - size += EbmlElementSize(libwebm::kMkvTrackType, type_); + uint64_t size = + EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_)); + size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_)); + size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_)); if (codec_id_) size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_); if (codec_private_) @@ -676,15 +725,22 @@ uint64_t Track::PayloadSize() const { size += EbmlElementSize(libwebm::kMkvLanguage, language_); if (name_) size += EbmlElementSize(libwebm::kMkvName, name_); - if (max_block_additional_id_) + if (max_block_additional_id_) { size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID, - max_block_additional_id_); - if (codec_delay_) - size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_); - if (seek_pre_roll_) - size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_); - if (default_duration_) - size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_); + static_cast<uint64>(max_block_additional_id_)); + } + if (codec_delay_) { + size += EbmlElementSize(libwebm::kMkvCodecDelay, + static_cast<uint64>(codec_delay_)); + } + if (seek_pre_roll_) { + size += EbmlElementSize(libwebm::kMkvSeekPreRoll, + static_cast<uint64>(seek_pre_roll_)); + } + if (default_duration_) { + size += EbmlElementSize(libwebm::kMkvDefaultDuration, + static_cast<uint64>(default_duration_)); + } if (content_encoding_entries_size_ > 0) { uint64_t content_encodings_size = 0; @@ -722,55 +778,64 @@ bool Track::Write(IMkvWriter* writer) const { if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size)) return false; - uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_); - size += EbmlElementSize(libwebm::kMkvTrackUID, uid_); - size += EbmlElementSize(libwebm::kMkvTrackType, type_); + uint64_t size = + EbmlElementSize(libwebm::kMkvTrackNumber, static_cast<uint64>(number_)); + size += EbmlElementSize(libwebm::kMkvTrackUID, static_cast<uint64>(uid_)); + size += EbmlElementSize(libwebm::kMkvTrackType, static_cast<uint64>(type_)); if (codec_id_) size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_); if (codec_private_) size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_, - codec_private_length_); + static_cast<uint64>(codec_private_length_)); if (language_) size += EbmlElementSize(libwebm::kMkvLanguage, language_); if (name_) size += EbmlElementSize(libwebm::kMkvName, name_); if (max_block_additional_id_) size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID, - max_block_additional_id_); + static_cast<uint64>(max_block_additional_id_)); if (codec_delay_) - size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_); + size += EbmlElementSize(libwebm::kMkvCodecDelay, + static_cast<uint64>(codec_delay_)); if (seek_pre_roll_) - size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_); + size += EbmlElementSize(libwebm::kMkvSeekPreRoll, + static_cast<uint64>(seek_pre_roll_)); if (default_duration_) - size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_); + size += EbmlElementSize(libwebm::kMkvDefaultDuration, + static_cast<uint64>(default_duration_)); const int64_t payload_position = writer->Position(); if (payload_position < 0) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber, number_)) + if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber, + static_cast<uint64>(number_))) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID, uid_)) + if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID, + static_cast<uint64>(uid_))) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvTrackType, type_)) + if (!WriteEbmlElement(writer, libwebm::kMkvTrackType, + static_cast<uint64>(type_))) return false; if (max_block_additional_id_) { if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID, - max_block_additional_id_)) { + static_cast<uint64>(max_block_additional_id_))) { return false; } } if (codec_delay_) { - if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay, codec_delay_)) + if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay, + static_cast<uint64>(codec_delay_))) return false; } if (seek_pre_roll_) { - if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll, seek_pre_roll_)) + if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll, + static_cast<uint64>(seek_pre_roll_))) return false; } if (default_duration_) { if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration, - default_duration_)) + static_cast<uint64>(default_duration_))) return false; } if (codec_id_) { @@ -779,7 +844,7 @@ bool Track::Write(IMkvWriter* writer) const { } if (codec_private_) { if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_, - codec_private_length_)) + static_cast<uint64>(codec_private_length_))) return false; } if (language_) { @@ -890,14 +955,23 @@ void Track::set_name(const char* name) { // // Colour and its child elements -uint64_t PrimaryChromaticity::PrimaryChromaticityPayloadSize( +uint64_t PrimaryChromaticity::PrimaryChromaticitySize( libwebm::MkvId x_id, libwebm::MkvId y_id) const { - return EbmlElementSize(x_id, x) + EbmlElementSize(y_id, y); + return EbmlElementSize(x_id, x_) + EbmlElementSize(y_id, y_); } bool PrimaryChromaticity::Write(IMkvWriter* writer, libwebm::MkvId x_id, libwebm::MkvId y_id) const { - return WriteEbmlElement(writer, x_id, x) && WriteEbmlElement(writer, y_id, y); + if (!Valid()) { + return false; + } + return WriteEbmlElement(writer, x_id, x_) && + WriteEbmlElement(writer, y_id, y_); +} + +bool PrimaryChromaticity::Valid() const { + return (x_ >= kChromaticityMin && x_ <= kChromaticityMax && + y_ >= kChromaticityMin && y_ <= kChromaticityMax); } uint64_t MasteringMetadata::MasteringMetadataSize() const { @@ -909,6 +983,31 @@ uint64_t MasteringMetadata::MasteringMetadataSize() const { return size; } +bool MasteringMetadata::Valid() const { + if (luminance_min_ != kValueNotPresent) { + if (luminance_min_ < kMinLuminance || luminance_min_ > kMinLuminanceMax || + luminance_min_ > luminance_max_) { + return false; + } + } + if (luminance_max_ != kValueNotPresent) { + if (luminance_max_ < kMinLuminance || luminance_max_ > kMaxLuminanceMax || + luminance_max_ < luminance_min_) { + return false; + } + } + if (r_ && !r_->Valid()) + return false; + if (g_ && !g_->Valid()) + return false; + if (b_ && !b_->Valid()) + return false; + if (white_point_ && !white_point_->Valid()) + return false; + + return true; +} + bool MasteringMetadata::Write(IMkvWriter* writer) const { const uint64_t size = PayloadSize(); @@ -918,12 +1017,12 @@ bool MasteringMetadata::Write(IMkvWriter* writer) const { if (!WriteEbmlMasterElement(writer, libwebm::kMkvMasteringMetadata, size)) return false; - if (luminance_max != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max)) { + if (luminance_max_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max_)) { return false; } - if (luminance_min != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min)) { + if (luminance_min_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min_)) { return false; } if (r_ && @@ -984,25 +1083,25 @@ bool MasteringMetadata::SetChromaticity( uint64_t MasteringMetadata::PayloadSize() const { uint64_t size = 0; - if (luminance_max != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvLuminanceMax, luminance_max); - if (luminance_min != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvLuminanceMin, luminance_min); + if (luminance_max_ != kValueNotPresent) + size += EbmlElementSize(libwebm::kMkvLuminanceMax, luminance_max_); + if (luminance_min_ != kValueNotPresent) + size += EbmlElementSize(libwebm::kMkvLuminanceMin, luminance_min_); if (r_) { - size += r_->PrimaryChromaticityPayloadSize( - libwebm::kMkvPrimaryRChromaticityX, libwebm::kMkvPrimaryRChromaticityY); + size += r_->PrimaryChromaticitySize(libwebm::kMkvPrimaryRChromaticityX, + libwebm::kMkvPrimaryRChromaticityY); } if (g_) { - size += g_->PrimaryChromaticityPayloadSize( - libwebm::kMkvPrimaryGChromaticityX, libwebm::kMkvPrimaryGChromaticityY); + size += g_->PrimaryChromaticitySize(libwebm::kMkvPrimaryGChromaticityX, + libwebm::kMkvPrimaryGChromaticityY); } if (b_) { - size += b_->PrimaryChromaticityPayloadSize( - libwebm::kMkvPrimaryBChromaticityX, libwebm::kMkvPrimaryBChromaticityY); + size += b_->PrimaryChromaticitySize(libwebm::kMkvPrimaryBChromaticityX, + libwebm::kMkvPrimaryBChromaticityY); } if (white_point_) { - size += white_point_->PrimaryChromaticityPayloadSize( + size += white_point_->PrimaryChromaticitySize( libwebm::kMkvWhitePointChromaticityX, libwebm::kMkvWhitePointChromaticityY); } @@ -1019,6 +1118,33 @@ uint64_t Colour::ColourSize() const { return size; } +bool Colour::Valid() const { + if (mastering_metadata_ && !mastering_metadata_->Valid()) + return false; + if (matrix_coefficients_ != kValueNotPresent && + !IsMatrixCoefficientsValueValid(matrix_coefficients_)) { + return false; + } + if (chroma_siting_horz_ != kValueNotPresent && + !IsChromaSitingHorzValueValid(chroma_siting_horz_)) { + return false; + } + if (chroma_siting_vert_ != kValueNotPresent && + !IsChromaSitingVertValueValid(chroma_siting_vert_)) { + return false; + } + if (range_ != kValueNotPresent && !IsColourRangeValueValid(range_)) + return false; + if (transfer_characteristics_ != kValueNotPresent && + !IsTransferCharacteristicsValueValid(transfer_characteristics_)) { + return false; + } + if (primaries_ != kValueNotPresent && !IsPrimariesValueValid(primaries_)) + return false; + + return true; +} + bool Colour::Write(IMkvWriter* writer) const { const uint64_t size = PayloadSize(); @@ -1026,69 +1152,77 @@ bool Colour::Write(IMkvWriter* writer) const { if (size == 0) return true; + // Don't write an invalid element. + if (!Valid()) + return false; + if (!WriteEbmlMasterElement(writer, libwebm::kMkvColour, size)) return false; - if (matrix_coefficients != kValueNotPresent && + if (matrix_coefficients_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvMatrixCoefficients, - matrix_coefficients)) { + static_cast<uint64>(matrix_coefficients_))) { return false; } - if (bits_per_channel != kValueNotPresent && + if (bits_per_channel_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvBitsPerChannel, - bits_per_channel)) { + static_cast<uint64>(bits_per_channel_))) { return false; } - if (chroma_subsampling_horz != kValueNotPresent && + if (chroma_subsampling_horz_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingHorz, - chroma_subsampling_horz)) { + static_cast<uint64>(chroma_subsampling_horz_))) { return false; } - if (chroma_subsampling_vert != kValueNotPresent && + if (chroma_subsampling_vert_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingVert, - chroma_subsampling_vert)) { + static_cast<uint64>(chroma_subsampling_vert_))) { return false; } - if (cb_subsampling_horz != kValueNotPresent && + if (cb_subsampling_horz_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingHorz, - cb_subsampling_horz)) { + static_cast<uint64>(cb_subsampling_horz_))) { return false; } - if (cb_subsampling_vert != kValueNotPresent && + if (cb_subsampling_vert_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingVert, - cb_subsampling_vert)) { + static_cast<uint64>(cb_subsampling_vert_))) { return false; } - if (chroma_siting_horz != kValueNotPresent && + if (chroma_siting_horz_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvChromaSitingHorz, - chroma_siting_horz)) { + static_cast<uint64>(chroma_siting_horz_))) { return false; } - if (chroma_siting_vert != kValueNotPresent && + if (chroma_siting_vert_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvChromaSitingVert, - chroma_siting_vert)) { + static_cast<uint64>(chroma_siting_vert_))) { return false; } - if (range != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvRange, range)) { + if (range_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvRange, + static_cast<uint64>(range_))) { return false; } - if (transfer_characteristics != kValueNotPresent && + if (transfer_characteristics_ != kValueNotPresent && !WriteEbmlElement(writer, libwebm::kMkvTransferCharacteristics, - transfer_characteristics)) { + static_cast<uint64>(transfer_characteristics_))) { return false; } - if (primaries != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvPrimaries, primaries)) { + if (primaries_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvPrimaries, + static_cast<uint64>(primaries_))) { return false; } - if (max_cll != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvMaxCLL, max_cll)) { + if (max_cll_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvMaxCLL, + static_cast<uint64>(max_cll_))) { return false; } - if (max_fall != kValueNotPresent && - !WriteEbmlElement(writer, libwebm::kMkvMaxFALL, max_fall)) { + if (max_fall_ != kValueNotPresent && + !WriteEbmlElement(writer, libwebm::kMkvMaxFALL, + static_cast<uint64>(max_fall_))) { return false; } @@ -1103,8 +1237,8 @@ bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) { if (!mm_ptr.get()) return false; - mm_ptr->luminance_max = mastering_metadata.luminance_max; - mm_ptr->luminance_min = mastering_metadata.luminance_min; + mm_ptr->set_luminance_max(mastering_metadata.luminance_max()); + mm_ptr->set_luminance_min(mastering_metadata.luminance_min()); if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(), mastering_metadata.b(), @@ -1120,38 +1254,56 @@ bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) { uint64_t Colour::PayloadSize() const { uint64_t size = 0; - if (matrix_coefficients != kValueNotPresent) - size += - EbmlElementSize(libwebm::kMkvMatrixCoefficients, matrix_coefficients); - if (bits_per_channel != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvBitsPerChannel, bits_per_channel); - if (chroma_subsampling_horz != kValueNotPresent) + if (matrix_coefficients_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvMatrixCoefficients, + static_cast<uint64>(matrix_coefficients_)); + } + if (bits_per_channel_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvBitsPerChannel, + static_cast<uint64>(bits_per_channel_)); + } + if (chroma_subsampling_horz_ != kValueNotPresent) { size += EbmlElementSize(libwebm::kMkvChromaSubsamplingHorz, - chroma_subsampling_horz); - if (chroma_subsampling_vert != kValueNotPresent) + static_cast<uint64>(chroma_subsampling_horz_)); + } + if (chroma_subsampling_vert_ != kValueNotPresent) { size += EbmlElementSize(libwebm::kMkvChromaSubsamplingVert, - chroma_subsampling_vert); - if (cb_subsampling_horz != kValueNotPresent) - size += - EbmlElementSize(libwebm::kMkvCbSubsamplingHorz, cb_subsampling_horz); - if (cb_subsampling_vert != kValueNotPresent) - size += - EbmlElementSize(libwebm::kMkvCbSubsamplingVert, cb_subsampling_vert); - if (chroma_siting_horz != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvChromaSitingHorz, chroma_siting_horz); - if (chroma_siting_vert != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvChromaSitingVert, chroma_siting_vert); - if (range != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvRange, range); - if (transfer_characteristics != kValueNotPresent) + static_cast<uint64>(chroma_subsampling_vert_)); + } + if (cb_subsampling_horz_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvCbSubsamplingHorz, + static_cast<uint64>(cb_subsampling_horz_)); + } + if (cb_subsampling_vert_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvCbSubsamplingVert, + static_cast<uint64>(cb_subsampling_vert_)); + } + if (chroma_siting_horz_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvChromaSitingHorz, + static_cast<uint64>(chroma_siting_horz_)); + } + if (chroma_siting_vert_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvChromaSitingVert, + static_cast<uint64>(chroma_siting_vert_)); + } + if (range_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvRange, static_cast<uint64>(range_)); + } + if (transfer_characteristics_ != kValueNotPresent) { size += EbmlElementSize(libwebm::kMkvTransferCharacteristics, - transfer_characteristics); - if (primaries != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvPrimaries, primaries); - if (max_cll != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvMaxCLL, max_cll); - if (max_fall != kValueNotPresent) - size += EbmlElementSize(libwebm::kMkvMaxFALL, max_fall); + static_cast<uint64>(transfer_characteristics_)); + } + if (primaries_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvPrimaries, + static_cast<uint64>(primaries_)); + } + if (max_cll_ != kValueNotPresent) { + size += EbmlElementSize(libwebm::kMkvMaxCLL, static_cast<uint64>(max_cll_)); + } + if (max_fall_ != kValueNotPresent) { + size += + EbmlElementSize(libwebm::kMkvMaxFALL, static_cast<uint64>(max_fall_)); + } if (mastering_metadata_) size += mastering_metadata_->MasteringMetadataSize(); @@ -1161,12 +1313,103 @@ uint64_t Colour::PayloadSize() const { /////////////////////////////////////////////////////////////// // +// Projection element + +uint64_t Projection::ProjectionSize() const { + uint64_t size = PayloadSize(); + + if (size > 0) + size += EbmlMasterElementSize(libwebm::kMkvProjection, size); + + return size; +} + +bool Projection::Write(IMkvWriter* writer) const { + const uint64_t size = PayloadSize(); + + // Don't write an empty element. + if (size == 0) + return true; + + if (!WriteEbmlMasterElement(writer, libwebm::kMkvProjection, size)) + return false; + + if (!WriteEbmlElement(writer, libwebm::kMkvProjectionType, + static_cast<uint64>(type_))) { + return false; + } + + if (private_data_length_ > 0 && private_data_ != NULL && + !WriteEbmlElement(writer, libwebm::kMkvProjectionPrivate, private_data_, + private_data_length_)) { + return false; + } + + if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseYaw, pose_yaw_)) + return false; + + if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPosePitch, + pose_pitch_)) { + return false; + } + + if (!WriteEbmlElement(writer, libwebm::kMkvProjectionPoseRoll, pose_roll_)) { + return false; + } + + return true; +} + +bool Projection::SetProjectionPrivate(const uint8_t* data, + uint64_t data_length) { + if (data == NULL || data_length == 0) { + return false; + } + + if (data_length != static_cast<size_t>(data_length)) { + return false; + } + + uint8_t* new_private_data = + new (std::nothrow) uint8_t[static_cast<size_t>(data_length)]; + if (new_private_data == NULL) { + return false; + } + + delete[] private_data_; + private_data_ = new_private_data; + private_data_length_ = data_length; + memcpy(private_data_, data, static_cast<size_t>(data_length)); + + return true; +} + +uint64_t Projection::PayloadSize() const { + uint64_t size = + EbmlElementSize(libwebm::kMkvProjection, static_cast<uint64>(type_)); + + if (private_data_length_ > 0 && private_data_ != NULL) { + size += EbmlElementSize(libwebm::kMkvProjectionPrivate, private_data_, + private_data_length_); + } + + size += EbmlElementSize(libwebm::kMkvProjectionPoseYaw, pose_yaw_); + size += EbmlElementSize(libwebm::kMkvProjectionPosePitch, pose_pitch_); + size += EbmlElementSize(libwebm::kMkvProjectionPoseRoll, pose_roll_); + + return size; +} + +/////////////////////////////////////////////////////////////// +// // VideoTrack Class VideoTrack::VideoTrack(unsigned int* seed) : Track(seed), display_height_(0), display_width_(0), + pixel_height_(0), + pixel_width_(0), crop_left_(0), crop_right_(0), crop_top_(0), @@ -1176,9 +1419,13 @@ VideoTrack::VideoTrack(unsigned int* seed) stereo_mode_(0), alpha_mode_(0), width_(0), - colour_(NULL) {} + colour_(NULL), + projection_(NULL) {} -VideoTrack::~VideoTrack() { delete colour_; } +VideoTrack::~VideoTrack() { + delete colour_; + delete projection_; +} bool VideoTrack::SetStereoMode(uint64_t stereo_mode) { if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst && @@ -1221,40 +1468,52 @@ bool VideoTrack::Write(IMkvWriter* writer) const { if (payload_position < 0) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvPixelWidth, width_)) + if (!WriteEbmlElement( + writer, libwebm::kMkvPixelWidth, + static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_))) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvPixelHeight, height_)) + if (!WriteEbmlElement( + writer, libwebm::kMkvPixelHeight, + static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_))) return false; if (display_width_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth, display_width_)) + if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth, + static_cast<uint64>(display_width_))) return false; } if (display_height_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight, display_height_)) + if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight, + static_cast<uint64>(display_height_))) return false; } if (crop_left_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft, crop_left_)) + if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft, + static_cast<uint64>(crop_left_))) return false; } if (crop_right_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight, crop_right_)) + if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight, + static_cast<uint64>(crop_right_))) return false; } if (crop_top_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop, crop_top_)) + if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop, + static_cast<uint64>(crop_top_))) return false; } if (crop_bottom_ > 0) { - if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom, crop_bottom_)) + if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom, + static_cast<uint64>(crop_bottom_))) return false; } if (stereo_mode_ > kMono) { - if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode, stereo_mode_)) + if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode, + static_cast<uint64>(stereo_mode_))) return false; } if (alpha_mode_ > kNoAlpha) { - if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode, alpha_mode_)) + if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode, + static_cast<uint64>(alpha_mode_))) return false; } if (frame_rate_ > 0.0) { @@ -1267,6 +1526,10 @@ bool VideoTrack::Write(IMkvWriter* writer) const { if (!colour_->Write(writer)) return false; } + if (projection_) { + if (!projection_->Write(writer)) + return false; + } const int64_t stop_position = writer->Position(); if (stop_position < 0 || @@ -1287,47 +1550,83 @@ bool VideoTrack::SetColour(const Colour& colour) { return false; } - colour_ptr->matrix_coefficients = colour.matrix_coefficients; - colour_ptr->bits_per_channel = colour.bits_per_channel; - colour_ptr->chroma_subsampling_horz = colour.chroma_subsampling_horz; - colour_ptr->chroma_subsampling_vert = colour.chroma_subsampling_vert; - colour_ptr->cb_subsampling_horz = colour.cb_subsampling_horz; - colour_ptr->cb_subsampling_vert = colour.cb_subsampling_vert; - colour_ptr->chroma_siting_horz = colour.chroma_siting_horz; - colour_ptr->chroma_siting_vert = colour.chroma_siting_vert; - colour_ptr->range = colour.range; - colour_ptr->transfer_characteristics = colour.transfer_characteristics; - colour_ptr->primaries = colour.primaries; - colour_ptr->max_cll = colour.max_cll; - colour_ptr->max_fall = colour.max_fall; + colour_ptr->set_matrix_coefficients(colour.matrix_coefficients()); + colour_ptr->set_bits_per_channel(colour.bits_per_channel()); + colour_ptr->set_chroma_subsampling_horz(colour.chroma_subsampling_horz()); + colour_ptr->set_chroma_subsampling_vert(colour.chroma_subsampling_vert()); + colour_ptr->set_cb_subsampling_horz(colour.cb_subsampling_horz()); + colour_ptr->set_cb_subsampling_vert(colour.cb_subsampling_vert()); + colour_ptr->set_chroma_siting_horz(colour.chroma_siting_horz()); + colour_ptr->set_chroma_siting_vert(colour.chroma_siting_vert()); + colour_ptr->set_range(colour.range()); + colour_ptr->set_transfer_characteristics(colour.transfer_characteristics()); + colour_ptr->set_primaries(colour.primaries()); + colour_ptr->set_max_cll(colour.max_cll()); + colour_ptr->set_max_fall(colour.max_fall()); + delete colour_; colour_ = colour_ptr.release(); return true; } +bool VideoTrack::SetProjection(const Projection& projection) { + std::auto_ptr<Projection> projection_ptr(new Projection()); + if (!projection_ptr.get()) + return false; + + if (projection.private_data()) { + if (!projection_ptr->SetProjectionPrivate( + projection.private_data(), projection.private_data_length())) { + return false; + } + } + + projection_ptr->set_type(projection.type()); + projection_ptr->set_pose_yaw(projection.pose_yaw()); + projection_ptr->set_pose_pitch(projection.pose_pitch()); + projection_ptr->set_pose_roll(projection.pose_roll()); + delete projection_; + projection_ = projection_ptr.release(); + return true; +} + uint64_t VideoTrack::VideoPayloadSize() const { - uint64_t size = EbmlElementSize(libwebm::kMkvPixelWidth, width_); - size += EbmlElementSize(libwebm::kMkvPixelHeight, height_); + uint64_t size = EbmlElementSize( + libwebm::kMkvPixelWidth, + static_cast<uint64>((pixel_width_ > 0) ? pixel_width_ : width_)); + size += EbmlElementSize( + libwebm::kMkvPixelHeight, + static_cast<uint64>((pixel_height_ > 0) ? pixel_height_ : height_)); if (display_width_ > 0) - size += EbmlElementSize(libwebm::kMkvDisplayWidth, display_width_); + size += EbmlElementSize(libwebm::kMkvDisplayWidth, + static_cast<uint64>(display_width_)); if (display_height_ > 0) - size += EbmlElementSize(libwebm::kMkvDisplayHeight, display_height_); + size += EbmlElementSize(libwebm::kMkvDisplayHeight, + static_cast<uint64>(display_height_)); if (crop_left_ > 0) - size += EbmlElementSize(libwebm::kMkvPixelCropLeft, crop_left_); + size += EbmlElementSize(libwebm::kMkvPixelCropLeft, + static_cast<uint64>(crop_left_)); if (crop_right_ > 0) - size += EbmlElementSize(libwebm::kMkvPixelCropRight, crop_right_); + size += EbmlElementSize(libwebm::kMkvPixelCropRight, + static_cast<uint64>(crop_right_)); if (crop_top_ > 0) - size += EbmlElementSize(libwebm::kMkvPixelCropTop, crop_top_); + size += EbmlElementSize(libwebm::kMkvPixelCropTop, + static_cast<uint64>(crop_top_)); if (crop_bottom_ > 0) - size += EbmlElementSize(libwebm::kMkvPixelCropBottom, crop_bottom_); + size += EbmlElementSize(libwebm::kMkvPixelCropBottom, + static_cast<uint64>(crop_bottom_)); if (stereo_mode_ > kMono) - size += EbmlElementSize(libwebm::kMkvStereoMode, stereo_mode_); + size += EbmlElementSize(libwebm::kMkvStereoMode, + static_cast<uint64>(stereo_mode_)); if (alpha_mode_ > kNoAlpha) - size += EbmlElementSize(libwebm::kMkvAlphaMode, alpha_mode_); + size += EbmlElementSize(libwebm::kMkvAlphaMode, + static_cast<uint64>(alpha_mode_)); if (frame_rate_ > 0.0) size += EbmlElementSize(libwebm::kMkvFrameRate, static_cast<float>(frame_rate_)); if (colour_) size += colour_->ColourSize(); + if (projection_) + size += projection_->ProjectionSize(); return size; } @@ -1346,9 +1645,11 @@ uint64_t AudioTrack::PayloadSize() const { uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency, static_cast<float>(sample_rate_)); - size += EbmlElementSize(libwebm::kMkvChannels, channels_); + size += + EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_)); if (bit_depth_ > 0) - size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_); + size += + EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_)); size += EbmlMasterElementSize(libwebm::kMkvAudio, size); return parent_size + size; @@ -1361,9 +1662,11 @@ bool AudioTrack::Write(IMkvWriter* writer) const { // Calculate AudioSettings size. uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency, static_cast<float>(sample_rate_)); - size += EbmlElementSize(libwebm::kMkvChannels, channels_); + size += + EbmlElementSize(libwebm::kMkvChannels, static_cast<uint64>(channels_)); if (bit_depth_ > 0) - size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_); + size += + EbmlElementSize(libwebm::kMkvBitDepth, static_cast<uint64>(bit_depth_)); if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size)) return false; @@ -1375,10 +1678,12 @@ bool AudioTrack::Write(IMkvWriter* writer) const { if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency, static_cast<float>(sample_rate_))) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvChannels, channels_)) + if (!WriteEbmlElement(writer, libwebm::kMkvChannels, + static_cast<uint64>(channels_))) return false; if (bit_depth_ > 0) - if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth, bit_depth_)) + if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth, + static_cast<uint64>(bit_depth_))) return false; const int64_t stop_position = writer->Position(); @@ -1398,6 +1703,10 @@ const char Tracks::kVorbisCodecId[] = "A_VORBIS"; const char Tracks::kVp8CodecId[] = "V_VP8"; const char Tracks::kVp9CodecId[] = "V_VP9"; const char Tracks::kVp10CodecId[] = "V_VP10"; +const char Tracks::kWebVttCaptionsId[] = "D_WEBVTT/CAPTIONS"; +const char Tracks::kWebVttDescriptionsId[] = "D_WEBVTT/DESCRIPTIONS"; +const char Tracks::kWebVttMetadataId[] = "D_WEBVTT/METADATA"; +const char Tracks::kWebVttSubtitlesId[] = "D_WEBVTT/SUBTITLES"; Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {} @@ -1650,9 +1959,11 @@ bool Chapter::ExpandDisplaysArray() { uint64_t Chapter::WriteAtom(IMkvWriter* writer) const { uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapterStringUID, id_) + - EbmlElementSize(libwebm::kMkvChapterUID, uid_) + - EbmlElementSize(libwebm::kMkvChapterTimeStart, start_timecode_) + - EbmlElementSize(libwebm::kMkvChapterTimeEnd, end_timecode_); + EbmlElementSize(libwebm::kMkvChapterUID, static_cast<uint64>(uid_)) + + EbmlElementSize(libwebm::kMkvChapterTimeStart, + static_cast<uint64>(start_timecode_)) + + EbmlElementSize(libwebm::kMkvChapterTimeEnd, + static_cast<uint64>(end_timecode_)); for (int idx = 0; idx < displays_count_; ++idx) { const Display& d = displays_[idx]; @@ -1674,13 +1985,16 @@ uint64_t Chapter::WriteAtom(IMkvWriter* writer) const { if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_)) return 0; - if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID, uid_)) + if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID, + static_cast<uint64>(uid_))) return 0; - if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart, start_timecode_)) + if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart, + static_cast<uint64>(start_timecode_))) return 0; - if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd, end_timecode_)) + if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd, + static_cast<uint64>(end_timecode_))) return 0; for (int idx = 0; idx < displays_count_; ++idx) { @@ -2125,7 +2439,17 @@ Cluster::Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale, write_last_frame_with_duration_(write_last_frame_with_duration), writer_(NULL) {} -Cluster::~Cluster() {} +Cluster::~Cluster() { + // Delete any stored frames that are left behind. This will happen if the + // Cluster was not Finalized for whatever reason. + while (!stored_frames_.empty()) { + while (!stored_frames_.begin()->second.empty()) { + delete stored_frames_.begin()->second.front(); + stored_frames_.begin()->second.pop_front(); + } + stored_frames_.erase(stored_frames_.begin()->first); + } +} bool Cluster::Init(IMkvWriter* ptr_writer) { if (!ptr_writer) { @@ -2421,10 +2745,10 @@ bool SeekHead::Finalize(IMkvWriter* writer) const { for (int32_t i = 0; i < kSeekEntryCount; ++i) { if (seek_entry_id_[i] != 0) { - entry_size[i] = EbmlElementSize( - libwebm::kMkvSeekID, static_cast<uint64_t>(seek_entry_id_[i])); - entry_size[i] += - EbmlElementSize(libwebm::kMkvSeekPosition, seek_entry_pos_[i]); + entry_size[i] = EbmlElementSize(libwebm::kMkvSeekID, + static_cast<uint64>(seek_entry_id_[i])); + entry_size[i] += EbmlElementSize( + libwebm::kMkvSeekPosition, static_cast<uint64>(seek_entry_pos_[i])); payload_size += EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) + @@ -2449,11 +2773,11 @@ bool SeekHead::Finalize(IMkvWriter* writer) const { return false; if (!WriteEbmlElement(writer, libwebm::kMkvSeekID, - static_cast<uint64_t>(seek_entry_id_[i]))) + static_cast<uint64>(seek_entry_id_[i]))) return false; if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition, - seek_entry_pos_[i])) + static_cast<uint64>(seek_entry_pos_[i]))) return false; } } @@ -2522,8 +2846,10 @@ bool SeekHead::SetSeekEntry(int index, uint32_t id, uint64_t position) { uint64_t SeekHead::MaxEntrySize() const { const uint64_t max_entry_payload_size = - EbmlElementSize(libwebm::kMkvSeekID, UINT64_C(0xffffffff)) + - EbmlElementSize(libwebm::kMkvSeekPosition, UINT64_C(0xffffffffffffffff)); + EbmlElementSize(libwebm::kMkvSeekID, + static_cast<uint64>(UINT64_C(0xffffffff))) + + EbmlElementSize(libwebm::kMkvSeekPosition, + static_cast<uint64>(UINT64_C(0xffffffffffffffff))); const uint64_t max_entry_size = EbmlMasterElementSize(libwebm::kMkvSeek, max_entry_payload_size) + max_entry_payload_size; @@ -2613,7 +2939,8 @@ bool SegmentInfo::Write(IMkvWriter* writer) { if (!writer || !muxing_app_ || !writing_app_) return false; - uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale, timecode_scale_); + uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale, + static_cast<uint64>(timecode_scale_)); if (duration_ > 0.0) size += EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_)); @@ -2629,7 +2956,8 @@ bool SegmentInfo::Write(IMkvWriter* writer) { if (payload_position < 0) return false; - if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale, timecode_scale_)) + if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale, + static_cast<uint64>(timecode_scale_))) return false; if (duration_ > 0.0) { @@ -2725,10 +3053,12 @@ Segment::Segment() output_cues_(true), accurate_cluster_duration_(false), fixed_size_cluster_timecode_(false), + estimate_file_duration_(true), payload_pos_(0), size_position_(0), doc_type_version_(kDefaultDocTypeVersion), doc_type_version_written_(0), + duration_(0.0), writer_cluster_(NULL), writer_cues_(NULL), writer_header_(NULL) { @@ -2833,6 +3163,10 @@ bool Segment::Init(IMkvWriter* ptr_writer) { writer_cluster_ = ptr_writer; writer_cues_ = ptr_writer; writer_header_ = ptr_writer; + memset(&track_frames_written_, 0, + sizeof(track_frames_written_[0]) * kMaxTrackNumber); + memset(&last_track_timestamp_, 0, + sizeof(last_track_timestamp_[0]) * kMaxTrackNumber); return segment_info_.Init(); } @@ -2876,7 +3210,10 @@ bool Segment::Finalize() { if (WriteFramesAll() < 0) return false; - if (cluster_list_size_ > 0) { + // In kLive mode, call Cluster::Finalize only if |accurate_cluster_duration_| + // is set. In all other modes, always call Cluster::Finalize. + if ((mode_ == kLive ? accurate_cluster_duration_ : true) && + cluster_list_size_ > 0) { // Update last cluster's size Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1]; @@ -2892,9 +3229,30 @@ bool Segment::Finalize() { chunk_count_++; } - const double duration = + double duration = (static_cast<double>(last_timestamp_) + last_block_duration_) / segment_info_.timecode_scale(); + if (duration_ > 0.0) { + duration = duration_; + } else { + if (last_block_duration_ == 0 && estimate_file_duration_) { + const int num_tracks = static_cast<int>(tracks_.track_entries_size()); + for (int i = 0; i < num_tracks; ++i) { + if (track_frames_written_[i] < 2) + continue; + + // Estimate the duration for the last block of a Track. + const double nano_per_frame = + static_cast<double>(last_track_timestamp_[i]) / + (track_frames_written_[i] - 1); + const double track_duration = + (last_track_timestamp_[i] + nano_per_frame) / + segment_info_.timecode_scale(); + if (track_duration > duration) + duration = track_duration; + } + } + } segment_info_.set_duration(duration); if (!segment_info_.Finalize(writer_header_)) return false; @@ -2941,7 +3299,9 @@ bool Segment::Finalize() { if (writer_header_->Position(0)) return false; - if (!WriteEbmlHeader(writer_header_, doc_type_version_)) + const char* const doc_type = + DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska; + if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type)) return false; if (writer_header_->Position() != ebml_header_size_) return false; @@ -3138,7 +3498,10 @@ bool Segment::AddGenericFrame(const Frame* frame) { Frame* const new_frame = new (std::nothrow) Frame(); if (!new_frame || !new_frame->CopyFrom(*frame)) return false; - return QueueFrame(new_frame); + if (!QueueFrame(new_frame)) + return false; + track_frames_written_[frame->track_number() - 1]++; + return true; } if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(), @@ -3178,10 +3541,10 @@ bool Segment::AddGenericFrame(const Frame* frame) { last_timestamp_ = frame->timestamp(); last_track_timestamp_[frame->track_number() - 1] = frame->timestamp(); last_block_duration_ = frame->duration(); + track_frames_written_[frame->track_number() - 1]++; if (frame_created) delete frame; - return true; } @@ -3292,8 +3655,9 @@ Track* Segment::GetTrackByNumber(uint64_t track_number) const { bool Segment::WriteSegmentHeader() { UpdateDocTypeVersion(); - // TODO(fgalligan): Support more than one segment. - if (!WriteEbmlHeader(writer_header_, doc_type_version_)) + const char* const doc_type = + DocTypeIsWebm() ? kDocTypeWebm : kDocTypeMatroska; + if (!WriteEbmlHeader(writer_header_, doc_type_version_, doc_type)) return false; doc_type_version_written_ = doc_type_version_; ebml_header_size_ = static_cast<int32_t>(writer_header_->Position()); @@ -3766,4 +4130,35 @@ bool Segment::WriteFramesLessThan(uint64_t timestamp) { return true; } +bool Segment::DocTypeIsWebm() const { + const int kNumCodecIds = 9; + + // TODO(vigneshv): Tweak .clang-format. + const char* kWebmCodecIds[kNumCodecIds] = { + Tracks::kOpusCodecId, Tracks::kVorbisCodecId, + Tracks::kVp8CodecId, Tracks::kVp9CodecId, + Tracks::kVp10CodecId, Tracks::kWebVttCaptionsId, + Tracks::kWebVttDescriptionsId, Tracks::kWebVttMetadataId, + Tracks::kWebVttSubtitlesId}; + + const int num_tracks = static_cast<int>(tracks_.track_entries_size()); + for (int track_index = 0; track_index < num_tracks; ++track_index) { + const Track* const track = tracks_.GetTrackByIndex(track_index); + const std::string codec_id = track->codec_id(); + + bool id_is_webm = false; + for (int id_index = 0; id_index < kNumCodecIds; ++id_index) { + if (codec_id == kWebmCodecIds[id_index]) { + id_is_webm = true; + break; + } + } + + if (!id_is_webm) + return false; + } + + return true; +} + } // namespace mkvmuxer diff --git a/third_party/libwebm/mkvmuxer/mkvmuxer.h b/third_party/libwebm/mkvmuxer/mkvmuxer.h index 55ba07196..46b0029dc 100644 --- a/third_party/libwebm/mkvmuxer/mkvmuxer.h +++ b/third_party/libwebm/mkvmuxer/mkvmuxer.h @@ -64,6 +64,12 @@ class IMkvWriter { LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter); }; +// Writes out the EBML header for a WebM file, but allows caller to specify +// DocType. This function must be called before any other libwebm writing +// functions are called. +bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version, + const char* const doc_type); + // Writes out the EBML header for a WebM file. This function must be called // before any other libwebm writing functions are called. bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version); @@ -348,26 +354,42 @@ class ContentEncoding { /////////////////////////////////////////////////////////////// // Colour element. -struct PrimaryChromaticity { - PrimaryChromaticity(float x_val, float y_val) : x(x_val), y(y_val) {} - PrimaryChromaticity() : x(0), y(0) {} +class PrimaryChromaticity { + public: + static const float kChromaticityMin; + static const float kChromaticityMax; + + PrimaryChromaticity(float x_val, float y_val) : x_(x_val), y_(y_val) {} + PrimaryChromaticity() : x_(0), y_(0) {} ~PrimaryChromaticity() {} - uint64_t PrimaryChromaticityPayloadSize(libwebm::MkvId x_id, - libwebm::MkvId y_id) const; + + // Returns sum of |x_id| and |y_id| element id sizes and payload sizes. + uint64_t PrimaryChromaticitySize(libwebm::MkvId x_id, + libwebm::MkvId y_id) const; + bool Valid() const; bool Write(IMkvWriter* writer, libwebm::MkvId x_id, libwebm::MkvId y_id) const; - float x; - float y; + float x() const { return x_; } + void set_x(float new_x) { x_ = new_x; } + float y() const { return y_; } + void set_y(float new_y) { y_ = new_y; } + + private: + float x_; + float y_; }; class MasteringMetadata { public: static const float kValueNotPresent; + static const float kMinLuminance; + static const float kMinLuminanceMax; + static const float kMaxLuminanceMax; MasteringMetadata() - : luminance_max(kValueNotPresent), - luminance_min(kValueNotPresent), + : luminance_max_(kValueNotPresent), + luminance_min_(kValueNotPresent), r_(NULL), g_(NULL), b_(NULL), @@ -381,6 +403,7 @@ class MasteringMetadata { // Returns total size of the MasteringMetadata element. uint64_t MasteringMetadataSize() const; + bool Valid() const; bool Write(IMkvWriter* writer) const; // Copies non-null chromaticity. @@ -393,13 +416,21 @@ class MasteringMetadata { const PrimaryChromaticity* b() const { return b_; } const PrimaryChromaticity* white_point() const { return white_point_; } - float luminance_max; - float luminance_min; + float luminance_max() const { return luminance_max_; } + void set_luminance_max(float luminance_max) { + luminance_max_ = luminance_max; + } + float luminance_min() const { return luminance_min_; } + void set_luminance_min(float luminance_min) { + luminance_min_ = luminance_min; + } private: // Returns size of MasteringMetadata child elements. uint64_t PayloadSize() const; + float luminance_max_; + float luminance_min_; PrimaryChromaticity* r_; PrimaryChromaticity* g_; PrimaryChromaticity* b_; @@ -408,26 +439,90 @@ class MasteringMetadata { class Colour { public: + enum MatrixCoefficients { + kGbr = 0, + kBt709 = 1, + kUnspecifiedMc = 2, + kReserved = 3, + kFcc = 4, + kBt470bg = 5, + kSmpte170MMc = 6, + kSmpte240MMc = 7, + kYcocg = 8, + kBt2020NonConstantLuminance = 9, + kBt2020ConstantLuminance = 10, + }; + enum ChromaSitingHorz { + kUnspecifiedCsh = 0, + kLeftCollocated = 1, + kHalfCsh = 2, + }; + enum ChromaSitingVert { + kUnspecifiedCsv = 0, + kTopCollocated = 1, + kHalfCsv = 2, + }; + enum Range { + kUnspecifiedCr = 0, + kBroadcastRange = 1, + kFullRange = 2, + kMcTcDefined = 3, // Defined by MatrixCoefficients/TransferCharacteristics. + }; + enum TransferCharacteristics { + kIturBt709Tc = 1, + kUnspecifiedTc = 2, + kReservedTc = 3, + kGamma22Curve = 4, + kGamma28Curve = 5, + kSmpte170MTc = 6, + kSmpte240MTc = 7, + kLinear = 8, + kLog = 9, + kLogSqrt = 10, + kIec6196624 = 11, + kIturBt1361ExtendedColourGamut = 12, + kIec6196621 = 13, + kIturBt202010bit = 14, + kIturBt202012bit = 15, + kSmpteSt2084 = 16, + kSmpteSt4281Tc = 17, + kAribStdB67Hlg = 18, + }; + enum Primaries { + kReservedP0 = 0, + kIturBt709P = 1, + kUnspecifiedP = 2, + kReservedP3 = 3, + kIturBt470M = 4, + kIturBt470Bg = 5, + kSmpte170MP = 6, + kSmpte240MP = 7, + kFilm = 8, + kIturBt2020 = 9, + kSmpteSt4281P = 10, + kJedecP22Phosphors = 22, + }; static const uint64_t kValueNotPresent; 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), + : 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_; } // Returns total size of the Colour element. uint64_t ColourSize() const; + bool Valid() const; bool Write(IMkvWriter* writer) const; // Deep copies |mastering_metadata|. @@ -437,28 +532,125 @@ class Colour { return mastering_metadata_; } - uint64_t matrix_coefficients; - uint64_t bits_per_channel; - uint64_t chroma_subsampling_horz; - uint64_t chroma_subsampling_vert; - uint64_t cb_subsampling_horz; - uint64_t cb_subsampling_vert; - uint64_t chroma_siting_horz; - uint64_t chroma_siting_vert; - uint64_t range; - uint64_t transfer_characteristics; - uint64_t primaries; - uint64_t max_cll; - uint64_t max_fall; + uint64_t matrix_coefficients() const { return matrix_coefficients_; } + void set_matrix_coefficients(uint64_t matrix_coefficients) { + matrix_coefficients_ = matrix_coefficients; + } + uint64_t bits_per_channel() const { return bits_per_channel_; } + void set_bits_per_channel(uint64_t bits_per_channel) { + bits_per_channel_ = bits_per_channel; + } + uint64_t chroma_subsampling_horz() const { return chroma_subsampling_horz_; } + void set_chroma_subsampling_horz(uint64_t chroma_subsampling_horz) { + chroma_subsampling_horz_ = chroma_subsampling_horz; + } + uint64_t chroma_subsampling_vert() const { return chroma_subsampling_vert_; } + void set_chroma_subsampling_vert(uint64_t chroma_subsampling_vert) { + chroma_subsampling_vert_ = chroma_subsampling_vert; + } + uint64_t cb_subsampling_horz() const { return cb_subsampling_horz_; } + void set_cb_subsampling_horz(uint64_t cb_subsampling_horz) { + cb_subsampling_horz_ = cb_subsampling_horz; + } + uint64_t cb_subsampling_vert() const { return cb_subsampling_vert_; } + void set_cb_subsampling_vert(uint64_t cb_subsampling_vert) { + cb_subsampling_vert_ = cb_subsampling_vert; + } + uint64_t chroma_siting_horz() const { return chroma_siting_horz_; } + void set_chroma_siting_horz(uint64_t chroma_siting_horz) { + chroma_siting_horz_ = chroma_siting_horz; + } + uint64_t chroma_siting_vert() const { return chroma_siting_vert_; } + void set_chroma_siting_vert(uint64_t chroma_siting_vert) { + chroma_siting_vert_ = chroma_siting_vert; + } + uint64_t range() const { return range_; } + void set_range(uint64_t range) { range_ = range; } + uint64_t transfer_characteristics() const { + return transfer_characteristics_; + } + void set_transfer_characteristics(uint64_t transfer_characteristics) { + transfer_characteristics_ = transfer_characteristics; + } + uint64_t primaries() const { return primaries_; } + void set_primaries(uint64_t primaries) { primaries_ = primaries; } + uint64_t max_cll() const { return max_cll_; } + void set_max_cll(uint64_t max_cll) { max_cll_ = max_cll; } + uint64_t max_fall() const { return max_fall_; } + void set_max_fall(uint64_t max_fall) { max_fall_ = max_fall; } private: // Returns size of Colour child elements. uint64_t PayloadSize() const; + uint64_t matrix_coefficients_; + uint64_t bits_per_channel_; + uint64_t chroma_subsampling_horz_; + uint64_t chroma_subsampling_vert_; + uint64_t cb_subsampling_horz_; + uint64_t cb_subsampling_vert_; + uint64_t chroma_siting_horz_; + uint64_t chroma_siting_vert_; + uint64_t range_; + uint64_t transfer_characteristics_; + uint64_t primaries_; + uint64_t max_cll_; + uint64_t max_fall_; + MasteringMetadata* mastering_metadata_; }; /////////////////////////////////////////////////////////////// +// Projection element. +class Projection { + public: + enum ProjectionType { + kTypeNotPresent = -1, + kRectangular = 0, + kEquirectangular = 1, + kCubeMap = 2, + kMesh = 3, + }; + static const uint64_t kValueNotPresent; + Projection() + : type_(kRectangular), + pose_yaw_(0.0), + pose_pitch_(0.0), + pose_roll_(0.0), + private_data_(NULL), + private_data_length_(0) {} + ~Projection() { delete[] private_data_; } + + uint64_t ProjectionSize() const; + bool Write(IMkvWriter* writer) const; + + bool SetProjectionPrivate(const uint8_t* private_data, + uint64_t private_data_length); + + ProjectionType type() const { return type_; } + void set_type(ProjectionType type) { type_ = type; } + float pose_yaw() const { return pose_yaw_; } + void set_pose_yaw(float pose_yaw) { pose_yaw_ = pose_yaw; } + float pose_pitch() const { return pose_pitch_; } + void set_pose_pitch(float pose_pitch) { pose_pitch_ = pose_pitch; } + float pose_roll() const { return pose_roll_; } + void set_pose_roll(float pose_roll) { pose_roll_ = pose_roll; } + uint8_t* private_data() const { return private_data_; } + uint64_t private_data_length() const { return private_data_length_; } + + private: + // Returns size of VideoProjection child elements. + uint64_t PayloadSize() const; + + ProjectionType type_; + float pose_yaw_; + float pose_pitch_; + float pose_roll_; + uint8_t* private_data_; + uint64_t private_data_length_; +}; + +/////////////////////////////////////////////////////////////// // Track element. class Track { public: @@ -581,6 +773,10 @@ class VideoTrack : public Track { uint64_t display_height() const { return display_height_; } void set_display_width(uint64_t width) { display_width_ = width; } uint64_t display_width() const { return display_width_; } + void set_pixel_height(uint64_t height) { pixel_height_ = height; } + uint64_t pixel_height() const { return pixel_height_; } + void set_pixel_width(uint64_t width) { pixel_width_ = width; } + uint64_t pixel_width() const { return pixel_width_; } void set_crop_left(uint64_t crop_left) { crop_left_ = crop_left; } uint64_t crop_left() const { return crop_left_; } @@ -605,6 +801,11 @@ class VideoTrack : public Track { // Deep copies |colour|. bool SetColour(const Colour& colour); + Projection* projection() { return projection_; } + + // Deep copies |projection|. + bool SetProjection(const Projection& projection); + private: // Returns the size in bytes of the Video element. uint64_t VideoPayloadSize() const; @@ -612,6 +813,8 @@ class VideoTrack : public Track { // Video track element names. uint64_t display_height_; uint64_t display_width_; + uint64_t pixel_height_; + uint64_t pixel_width_; uint64_t crop_left_; uint64_t crop_right_; uint64_t crop_top_; @@ -623,6 +826,7 @@ class VideoTrack : public Track { uint64_t width_; Colour* colour_; + Projection* projection_; LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack); }; @@ -670,6 +874,10 @@ class Tracks { static const char kVp8CodecId[]; static const char kVp9CodecId[]; static const char kVp10CodecId[]; + static const char kWebVttCaptionsId[]; + static const char kWebVttDescriptionsId[]; + static const char kWebVttMetadataId[]; + static const char kWebVttSubtitlesId[]; Tracks(); ~Tracks(); @@ -1294,8 +1502,8 @@ class Segment { kBeforeClusters = 0x1 // Position Cues before Clusters }; - const static uint32_t kDefaultDocTypeVersion = 2; - const static uint64_t kDefaultMaxClusterDuration = 30000000000ULL; + static const uint32_t kDefaultDocTypeVersion = 4; + static const uint64_t kDefaultMaxClusterDuration = 30000000000ULL; Segment(); ~Segment(); @@ -1481,7 +1689,16 @@ class Segment { Mode mode() const { return mode_; } CuesPosition cues_position() const { return cues_position_; } bool output_cues() const { return output_cues_; } + void set_estimate_file_duration(bool estimate_duration) { + estimate_file_duration_ = estimate_duration; + } + bool estimate_file_duration() const { return estimate_file_duration_; } const SegmentInfo* segment_info() const { return &segment_info_; } + void set_duration(double duration) { duration_ = duration; } + double duration() const { return duration_; } + + // Returns true when codec IDs are valid for WebM. + bool DocTypeIsWebm() const; private: // Checks if header information has been output and initialized. If not it @@ -1637,6 +1854,9 @@ class Segment { // Last timestamp in nanoseconds by track number added to a cluster. uint64_t last_track_timestamp_[kMaxTrackNumber]; + // Number of frames written per track. + uint64_t track_frames_written_[kMaxTrackNumber]; + // Maximum time in nanoseconds for a cluster duration. This variable is a // guideline and some clusters may have a longer duration. Default is 30 // seconds. @@ -1665,6 +1885,9 @@ class Segment { // Flag whether or not to write the Cluster Timecode using exactly 8 bytes. bool fixed_size_cluster_timecode_; + // Flag whether or not to estimate the file duration. + bool estimate_file_duration_; + // The size of the EBML header, used to validate the header if // WriteEbmlHeader() is called more than once. int32_t ebml_header_size_; @@ -1682,6 +1905,9 @@ class Segment { uint32_t doc_type_version_; uint32_t doc_type_version_written_; + // If |duration_| is > 0, then explicitly set the duration of the segment. + double duration_; + // Pointer to the writer objects. Not owned by this class. IMkvWriter* writer_cluster_; IMkvWriter* writer_cues_; diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc index 3562b8ab8..1ba17ac1b 100644 --- a/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc +++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc @@ -31,20 +31,20 @@ namespace { // Date elements are always 8 octets in size. const int kDateElementSize = 8; -uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, - int64_t timecode, uint64_t timecode_scale) { - uint64_t block_additional_elem_size = 0; - uint64_t block_addid_elem_size = 0; - uint64_t block_more_payload_size = 0; - uint64_t block_more_elem_size = 0; - uint64_t block_additions_payload_size = 0; - uint64_t block_additions_elem_size = 0; +uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode, + uint64 timecode_scale) { + uint64 block_additional_elem_size = 0; + uint64 block_addid_elem_size = 0; + uint64 block_more_payload_size = 0; + uint64 block_more_elem_size = 0; + uint64 block_additions_payload_size = 0; + uint64 block_additions_elem_size = 0; if (frame->additional()) { block_additional_elem_size = EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(), frame->additional_length()); - block_addid_elem_size = - EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id()); + block_addid_elem_size = EbmlElementSize( + libwebm::kMkvBlockAddID, static_cast<uint64>(frame->add_id())); block_more_payload_size = block_addid_elem_size + block_additional_elem_size; @@ -58,32 +58,33 @@ uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, block_additions_payload_size; } - uint64_t discard_padding_elem_size = 0; + uint64 discard_padding_elem_size = 0; if (frame->discard_padding() != 0) { discard_padding_elem_size = - EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding()); + EbmlElementSize(libwebm::kMkvDiscardPadding, + static_cast<int64>(frame->discard_padding())); } - const uint64_t reference_block_timestamp = + const uint64 reference_block_timestamp = frame->reference_block_timestamp() / timecode_scale; - uint64_t reference_block_elem_size = 0; + uint64 reference_block_elem_size = 0; if (!frame->is_key()) { reference_block_elem_size = EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp); } - const uint64_t duration = frame->duration() / timecode_scale; - uint64_t block_duration_elem_size = 0; + const uint64 duration = frame->duration() / timecode_scale; + uint64 block_duration_elem_size = 0; if (duration > 0) block_duration_elem_size = EbmlElementSize(libwebm::kMkvBlockDuration, duration); - const uint64_t block_payload_size = 4 + frame->length(); - const uint64_t block_elem_size = + const uint64 block_payload_size = 4 + frame->length(); + const uint64 block_elem_size = EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) + block_payload_size; - const uint64_t block_group_payload_size = + const uint64 block_group_payload_size = block_elem_size + block_additions_elem_size + block_duration_elem_size + discard_padding_elem_size + reference_block_elem_size; @@ -105,7 +106,7 @@ uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, if (SerializeInt(writer, 0, 1)) return 0; - if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length()))) + if (writer->Write(frame->frame(), static_cast<uint32>(frame->length()))) return 0; if (frame->additional()) { @@ -118,7 +119,8 @@ uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, block_more_payload_size)) return 0; - if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id())) + if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, + static_cast<uint64>(frame->add_id()))) return 0; if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional, @@ -129,7 +131,7 @@ uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, if (frame->discard_padding() != 0 && !WriteEbmlElement(writer, libwebm::kMkvDiscardPadding, - frame->discard_padding())) { + static_cast<int64>(frame->discard_padding()))) { return false; } @@ -148,38 +150,38 @@ uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame, block_group_payload_size; } -uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame, - int64_t timecode) { +uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame, + int64 timecode) { if (WriteID(writer, libwebm::kMkvSimpleBlock)) return 0; - const int32_t size = static_cast<int32_t>(frame->length()) + 4; + const int32 size = static_cast<int32>(frame->length()) + 4; if (WriteUInt(writer, size)) return 0; - if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number()))) + if (WriteUInt(writer, static_cast<uint64>(frame->track_number()))) return 0; if (SerializeInt(writer, timecode, 2)) return 0; - uint64_t flags = 0; + uint64 flags = 0; if (frame->is_key()) flags |= 0x80; if (SerializeInt(writer, flags, 1)) return 0; - if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length()))) + if (writer->Write(frame->frame(), static_cast<uint32>(frame->length()))) return 0; - return static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) + - GetCodedUIntSize(size) + 4 + frame->length()); + return GetUIntSize(libwebm::kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + + frame->length(); } } // namespace -int32_t GetCodedUIntSize(uint64_t value) { +int32 GetCodedUIntSize(uint64 value) { if (value < 0x000000000000007FULL) return 1; else if (value < 0x0000000000003FFFULL) @@ -197,7 +199,7 @@ int32_t GetCodedUIntSize(uint64_t value) { return 8; } -int32_t GetUIntSize(uint64_t value) { +int32 GetUIntSize(uint64 value) { if (value < 0x0000000000000100ULL) return 1; else if (value < 0x0000000000010000ULL) @@ -215,26 +217,26 @@ int32_t GetUIntSize(uint64_t value) { return 8; } -int32_t GetIntSize(int64_t value) { +int32 GetIntSize(int64 value) { // Doubling the requested value ensures positive values with their high bit // set are written with 0-padding to avoid flipping the signedness. - const uint64_t v = (value < 0) ? value ^ -1LL : value; + const uint64 v = (value < 0) ? value ^ -1LL : value; return GetUIntSize(2 * v); } -uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) { +uint64 EbmlMasterElementSize(uint64 type, uint64 value) { // Size of EBML ID - int32_t ebml_size = GetUIntSize(type); + int32 ebml_size = GetUIntSize(type); // Datasize ebml_size += GetCodedUIntSize(value); - return static_cast<uint64_t>(ebml_size); + return ebml_size; } -uint64_t EbmlElementSize(uint64_t type, int64_t value) { +uint64 EbmlElementSize(uint64 type, int64 value) { // Size of EBML ID - int32_t ebml_size = GetUIntSize(type); + int32 ebml_size = GetUIntSize(type); // Datasize ebml_size += GetIntSize(value); @@ -242,20 +244,19 @@ uint64_t EbmlElementSize(uint64_t type, int64_t value) { // Size of Datasize ebml_size++; - return static_cast<uint64_t>(ebml_size); + return ebml_size; } -uint64_t EbmlElementSize(uint64_t type, uint64_t value) { +uint64 EbmlElementSize(uint64 type, uint64 value) { return EbmlElementSize(type, value, 0); } -uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) { +uint64 EbmlElementSize(uint64 type, uint64 value, uint64 fixed_size) { // Size of EBML ID - uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type)); + uint64 ebml_size = GetUIntSize(type); // Datasize - ebml_size += - (fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value)); + ebml_size += (fixed_size > 0) ? fixed_size : GetUIntSize(value); // Size of Datasize ebml_size++; @@ -263,9 +264,9 @@ uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) { return ebml_size; } -uint64_t EbmlElementSize(uint64_t type, float /* value */) { +uint64 EbmlElementSize(uint64 type, float /* value */) { // Size of EBML ID - uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type)); + uint64 ebml_size = GetUIntSize(type); // Datasize ebml_size += sizeof(float); @@ -276,12 +277,12 @@ uint64_t EbmlElementSize(uint64_t type, float /* value */) { return ebml_size; } -uint64_t EbmlElementSize(uint64_t type, const char* value) { +uint64 EbmlElementSize(uint64 type, const char* value) { if (!value) return 0; // Size of EBML ID - uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type)); + uint64 ebml_size = GetUIntSize(type); // Datasize ebml_size += strlen(value); @@ -292,12 +293,12 @@ uint64_t EbmlElementSize(uint64_t type, const char* value) { return ebml_size; } -uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) { +uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) { if (!value) return 0; // Size of EBML ID - uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type)); + uint64 ebml_size = GetUIntSize(type); // Datasize ebml_size += size; @@ -308,9 +309,9 @@ uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) { return ebml_size; } -uint64_t EbmlDateElementSize(uint64_t type) { +uint64 EbmlDateElementSize(uint64 type) { // Size of EBML ID - uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type)); + uint64 ebml_size = GetUIntSize(type); // Datasize ebml_size += kDateElementSize; @@ -321,18 +322,18 @@ uint64_t EbmlDateElementSize(uint64_t type) { return ebml_size; } -int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) { +int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) { if (!writer || size < 1 || size > 8) return -1; - for (int32_t i = 1; i <= size; ++i) { - const int32_t byte_count = size - i; - const int32_t bit_count = byte_count * 8; + for (int32 i = 1; i <= size; ++i) { + const int32 byte_count = size - i; + const int32 bit_count = byte_count * 8; - const int64_t bb = value >> bit_count; - const uint8_t b = static_cast<uint8_t>(bb); + const int64 bb = value >> bit_count; + const uint8 b = static_cast<uint8>(bb); - const int32_t status = writer->Write(&b, 1); + const int32 status = writer->Write(&b, 1); if (status < 0) return status; @@ -341,26 +342,26 @@ int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) { return 0; } -int32_t SerializeFloat(IMkvWriter* writer, float f) { +int32 SerializeFloat(IMkvWriter* writer, float f) { if (!writer) return -1; - assert(sizeof(uint32_t) == sizeof(float)); + assert(sizeof(uint32) == sizeof(float)); // This union is merely used to avoid a reinterpret_cast from float& to // uint32& which will result in violation of strict aliasing. union U32 { - uint32_t u32; + uint32 u32; float f; } value; value.f = f; - for (int32_t i = 1; i <= 4; ++i) { - const int32_t byte_count = 4 - i; - const int32_t bit_count = byte_count * 8; + for (int32 i = 1; i <= 4; ++i) { + const int32 byte_count = 4 - i; + const int32 bit_count = byte_count * 8; - const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count); + const uint8 byte = static_cast<uint8>(value.u32 >> bit_count); - const int32_t status = writer->Write(&byte, 1); + const int32 status = writer->Write(&byte, 1); if (status < 0) return status; @@ -369,21 +370,21 @@ int32_t SerializeFloat(IMkvWriter* writer, float f) { return 0; } -int32_t WriteUInt(IMkvWriter* writer, uint64_t value) { +int32 WriteUInt(IMkvWriter* writer, uint64 value) { if (!writer) return -1; - int32_t size = GetCodedUIntSize(value); + int32 size = GetCodedUIntSize(value); return WriteUIntSize(writer, value, size); } -int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) { +int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) { if (!writer || size < 0 || size > 8) return -1; if (size > 0) { - const uint64_t bit = 1LL << (size * 7); + const uint64 bit = 1LL << (size * 7); if (value > (bit - 2)) return -1; @@ -391,11 +392,11 @@ int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) { value |= bit; } else { size = 1; - int64_t bit; + int64 bit; for (;;) { bit = 1LL << (size * 7); - const uint64_t max = bit - 2; + const uint64 max = bit - 2; if (value <= max) break; @@ -412,18 +413,18 @@ int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) { return SerializeInt(writer, value, size); } -int32_t WriteID(IMkvWriter* writer, uint64_t type) { +int32 WriteID(IMkvWriter* writer, uint64 type) { if (!writer) return -1; writer->ElementStartNotify(type, writer->Position()); - const int32_t size = GetUIntSize(type); + const int32 size = GetUIntSize(type); return SerializeInt(writer, type, size); } -bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) { +bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) { if (!writer) return false; @@ -436,19 +437,19 @@ bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) { return true; } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) { return WriteEbmlElement(writer, type, value, 0); } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value, - uint64_t fixed_size) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value, + uint64 fixed_size) { if (!writer) return false; if (WriteID(writer, type)) return false; - uint64_t size = static_cast<uint64_t>(GetUIntSize(value)); + uint64 size = GetUIntSize(value); if (fixed_size > 0) { if (size > fixed_size) return false; @@ -457,30 +458,30 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value, if (WriteUInt(writer, size)) return false; - if (SerializeInt(writer, value, static_cast<int32_t>(size))) + if (SerializeInt(writer, value, static_cast<int32>(size))) return false; return true; } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) { if (!writer) return false; if (WriteID(writer, type)) return 0; - const uint64_t size = GetIntSize(value); + const uint64 size = GetIntSize(value); if (WriteUInt(writer, size)) return false; - if (SerializeInt(writer, value, static_cast<int32_t>(size))) + if (SerializeInt(writer, value, static_cast<int32>(size))) return false; return true; } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) { if (!writer) return false; @@ -496,25 +497,25 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) { return true; } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) { if (!writer || !value) return false; if (WriteID(writer, type)) return false; - const uint64_t length = strlen(value); + const uint64 length = strlen(value); if (WriteUInt(writer, length)) return false; - if (writer->Write(value, static_cast<const uint32_t>(length))) + if (writer->Write(value, static_cast<const uint32>(length))) return false; return true; } -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value, - uint64_t size) { +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value, + uint64 size) { if (!writer || !value || size < 1) return false; @@ -524,13 +525,13 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value, if (WriteUInt(writer, size)) return false; - if (writer->Write(value, static_cast<uint32_t>(size))) + if (writer->Write(value, static_cast<uint32>(size))) return false; return true; } -bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) { +bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) { if (!writer) return false; @@ -546,8 +547,8 @@ bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) { return true; } -uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame, - Cluster* cluster) { +uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame, + Cluster* cluster) { if (!writer || !frame || !frame->IsValid() || !cluster || !cluster->timecode_scale()) return 0; @@ -556,7 +557,7 @@ uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame, // timecode for the cluster itself (remember that block timecode // is a signed, 16-bit integer). However, as a simplification we // only permit non-negative cluster-relative timecodes for blocks. - const int64_t relative_timecode = cluster->GetRelativeTimecode( + const int64 relative_timecode = cluster->GetRelativeTimecode( frame->timestamp() / cluster->timecode_scale()); if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode) return 0; @@ -567,20 +568,19 @@ uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame, cluster->timecode_scale()); } -uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) { +uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) { if (!writer) return false; // Subtract one for the void ID and the coded size. - uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1); - uint64_t void_size = - EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) + - void_entry_size; + uint64 void_entry_size = size - 1 - GetCodedUIntSize(size - 1); + uint64 void_size = EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) + + void_entry_size; if (void_size != size) return 0; - const int64_t payload_position = writer->Position(); + const int64 payload_position = writer->Position(); if (payload_position < 0) return 0; @@ -590,30 +590,29 @@ uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) { if (WriteUInt(writer, void_entry_size)) return 0; - const uint8_t value = 0; - for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) { + const uint8 value = 0; + for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) { if (writer->Write(&value, 1)) return 0; } - const int64_t stop_position = writer->Position(); + const int64 stop_position = writer->Position(); if (stop_position < 0 || - stop_position - payload_position != static_cast<int64_t>(void_size)) + stop_position - payload_position != static_cast<int64>(void_size)) return 0; return void_size; } -void GetVersion(int32_t* major, int32_t* minor, int32_t* build, - int32_t* revision) { +void GetVersion(int32* major, int32* minor, int32* build, int32* revision) { *major = 0; *minor = 2; *build = 1; *revision = 0; } -uint64_t MakeUID(unsigned int* seed) { - uint64_t uid = 0; +uint64 MakeUID(unsigned int* seed) { + uint64 uid = 0; #ifdef __MINGW32__ srand(*seed); @@ -625,21 +624,22 @@ uint64_t MakeUID(unsigned int* seed) { // TODO(fgalligan): Move random number generation to platform specific code. #ifdef _MSC_VER (void)seed; - const int32_t nn = rand(); + const int32 nn = rand(); #elif __ANDROID__ - int32_t temp_num = 1; + (void)seed; + int32 temp_num = 1; int fd = open("/dev/urandom", O_RDONLY); if (fd != -1) { read(fd, &temp_num, sizeof(temp_num)); close(fd); } - const int32_t nn = temp_num; + const int32 nn = temp_num; #elif defined __MINGW32__ - const int32_t nn = rand(); + const int32 nn = rand(); #else - const int32_t nn = rand_r(seed); + const int32 nn = rand_r(seed); #endif - const int32_t n = 0xFF & (nn >> 4); // throw away low-order bits + const int32 n = 0xFF & (nn >> 4); // throw away low-order bits uid |= n; } @@ -647,4 +647,97 @@ uint64_t MakeUID(unsigned int* seed) { return uid; } +bool IsMatrixCoefficientsValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kGbr: + case mkvmuxer::Colour::kBt709: + case mkvmuxer::Colour::kUnspecifiedMc: + case mkvmuxer::Colour::kReserved: + case mkvmuxer::Colour::kFcc: + case mkvmuxer::Colour::kBt470bg: + case mkvmuxer::Colour::kSmpte170MMc: + case mkvmuxer::Colour::kSmpte240MMc: + case mkvmuxer::Colour::kYcocg: + case mkvmuxer::Colour::kBt2020NonConstantLuminance: + case mkvmuxer::Colour::kBt2020ConstantLuminance: + return true; + } + return false; +} + +bool IsChromaSitingHorzValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kUnspecifiedCsh: + case mkvmuxer::Colour::kLeftCollocated: + case mkvmuxer::Colour::kHalfCsh: + return true; + } + return false; +} + +bool IsChromaSitingVertValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kUnspecifiedCsv: + case mkvmuxer::Colour::kTopCollocated: + case mkvmuxer::Colour::kHalfCsv: + return true; + } + return false; +} + +bool IsColourRangeValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kUnspecifiedCr: + case mkvmuxer::Colour::kBroadcastRange: + case mkvmuxer::Colour::kFullRange: + case mkvmuxer::Colour::kMcTcDefined: + return true; + } + return false; +} + +bool IsTransferCharacteristicsValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kIturBt709Tc: + case mkvmuxer::Colour::kUnspecifiedTc: + case mkvmuxer::Colour::kReservedTc: + case mkvmuxer::Colour::kGamma22Curve: + case mkvmuxer::Colour::kGamma28Curve: + case mkvmuxer::Colour::kSmpte170MTc: + case mkvmuxer::Colour::kSmpte240MTc: + case mkvmuxer::Colour::kLinear: + case mkvmuxer::Colour::kLog: + case mkvmuxer::Colour::kLogSqrt: + case mkvmuxer::Colour::kIec6196624: + case mkvmuxer::Colour::kIturBt1361ExtendedColourGamut: + case mkvmuxer::Colour::kIec6196621: + case mkvmuxer::Colour::kIturBt202010bit: + case mkvmuxer::Colour::kIturBt202012bit: + case mkvmuxer::Colour::kSmpteSt2084: + case mkvmuxer::Colour::kSmpteSt4281Tc: + case mkvmuxer::Colour::kAribStdB67Hlg: + return true; + } + return false; +} + +bool IsPrimariesValueValid(uint64_t value) { + switch (value) { + case mkvmuxer::Colour::kReservedP0: + case mkvmuxer::Colour::kIturBt709P: + case mkvmuxer::Colour::kUnspecifiedP: + case mkvmuxer::Colour::kReservedP3: + case mkvmuxer::Colour::kIturBt470M: + case mkvmuxer::Colour::kIturBt470Bg: + case mkvmuxer::Colour::kSmpte170MP: + case mkvmuxer::Colour::kSmpte240MP: + case mkvmuxer::Colour::kFilm: + case mkvmuxer::Colour::kIturBt2020: + case mkvmuxer::Colour::kSmpteSt4281P: + case mkvmuxer::Colour::kJedecP22Phosphors: + return true; + } + return false; +} + } // namespace mkvmuxer diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.h b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h index 0e21a2dcb..132388da5 100644 --- a/third_party/libwebm/mkvmuxer/mkvmuxerutil.h +++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h @@ -8,87 +8,104 @@ #ifndef MKVMUXER_MKVMUXERUTIL_H_ #define MKVMUXER_MKVMUXERUTIL_H_ -#include <stdint.h> +#include "mkvmuxertypes.h" + +#include "stdint.h" namespace mkvmuxer { class Cluster; class Frame; class IMkvWriter; -const uint64_t kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL; -const int64_t kMaxBlockTimecode = 0x07FFFLL; +// TODO(tomfinegan): mkvmuxer:: integer types continue to be used here because +// changing them causes pain for downstream projects. It would be nice if a +// solution that allows removal of the mkvmuxer:: integer types while avoiding +// pain for downstream users of libwebm. Considering that mkvmuxerutil.{cc,h} +// are really, for the great majority of cases, EBML size calculation and writer +// functions, perhaps a more EBML focused utility would be the way to go as a +// first step. + +const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL; +const int64 kMaxBlockTimecode = 0x07FFFLL; // Writes out |value| in Big Endian order. Returns 0 on success. -int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size); +int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size); // Returns the size in bytes of the element. -int32_t GetUIntSize(uint64_t value); -int32_t GetIntSize(int64_t value); -int32_t GetCodedUIntSize(uint64_t value); -uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value); -uint64_t EbmlElementSize(uint64_t type, int64_t value); -uint64_t EbmlElementSize(uint64_t type, uint64_t value); -uint64_t EbmlElementSize(uint64_t type, float value); -uint64_t EbmlElementSize(uint64_t type, const char* value); -uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size); -uint64_t EbmlDateElementSize(uint64_t type); +int32 GetUIntSize(uint64 value); +int32 GetIntSize(int64 value); +int32 GetCodedUIntSize(uint64 value); +uint64 EbmlMasterElementSize(uint64 type, uint64 value); +uint64 EbmlElementSize(uint64 type, int64 value); +uint64 EbmlElementSize(uint64 type, uint64 value); +uint64 EbmlElementSize(uint64 type, float value); +uint64 EbmlElementSize(uint64 type, const char* value); +uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size); +uint64 EbmlDateElementSize(uint64 type); // Returns the size in bytes of the element assuming that the element was // written using |fixed_size| bytes. If |fixed_size| is set to zero, then it // computes the necessary number of bytes based on |value|. -uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size); +uint64 EbmlElementSize(uint64 type, uint64 value, uint64 fixed_size); // Creates an EBML coded number from |value| and writes it out. The size of // the coded number is determined by the value of |value|. |value| must not // be in a coded form. Returns 0 on success. -int32_t WriteUInt(IMkvWriter* writer, uint64_t value); +int32 WriteUInt(IMkvWriter* writer, uint64 value); // Creates an EBML coded number from |value| and writes it out. The size of // the coded number is determined by the value of |size|. |value| must not // be in a coded form. Returns 0 on success. -int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size); +int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size); // Output an Mkv master element. Returns true if the element was written. -bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t value, uint64_t size); +bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 value, uint64 size); // Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the // ID to |SerializeInt|. Returns 0 on success. -int32_t WriteID(IMkvWriter* writer, uint64_t type); +int32 WriteID(IMkvWriter* writer, uint64 type); // Output an Mkv non-master element. Returns true if the element was written. -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value); -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value); -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value); -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value); -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value, - uint64_t size); -bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value, + uint64 size); +bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value); // Output an Mkv non-master element using fixed size. The element will be // written out using exactly |fixed_size| bytes. If |fixed_size| is set to zero // then it computes the necessary number of bytes based on |value|. Returns true // if the element was written. -bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value, - uint64_t fixed_size); +bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value, + uint64 fixed_size); // Output a Mkv Frame. It decides the correct element to write (Block vs // SimpleBlock) based on the parameters of the Frame. -uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame, - Cluster* cluster); +uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame, + Cluster* cluster); // Output a void element. |size| must be the entire size in bytes that will be // void. The function will calculate the size of the void header and subtract // it from |size|. -uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size); +uint64 WriteVoidElement(IMkvWriter* writer, uint64 size); // Returns the version number of the muxer in |major|, |minor|, |build|, // and |revision|. -void GetVersion(int32_t* major, int32_t* minor, int32_t* build, - int32_t* revision); +void GetVersion(int32* major, int32* minor, int32* build, int32* revision); // Returns a random number to be used for UID, using |seed| to seed // the random-number generator (see POSIX rand_r() for semantics). -uint64_t MakeUID(unsigned int* seed); +uint64 MakeUID(unsigned int* seed); + +// Colour field validation helpers. All return true when |value| is valid. +bool IsMatrixCoefficientsValueValid(uint64_t value); +bool IsChromaSitingHorzValueValid(uint64_t value); +bool IsChromaSitingVertValueValid(uint64_t value); +bool IsColourRangeValueValid(uint64_t value); +bool IsTransferCharacteristicsValueValid(uint64_t value); +bool IsPrimariesValueValid(uint64_t value); } // namespace mkvmuxer diff --git a/third_party/libwebm/mkvmuxer/mkvwriter.cc b/third_party/libwebm/mkvmuxer/mkvwriter.cc index ca48e149c..ec34e4df8 100644 --- a/third_party/libwebm/mkvmuxer/mkvwriter.cc +++ b/third_party/libwebm/mkvmuxer/mkvwriter.cc @@ -77,7 +77,7 @@ int32 MkvWriter::Position(int64 position) { #ifdef _MSC_VER return _fseeki64(file_, position, SEEK_SET); #else - return fseek(file_, position, SEEK_SET); + return fseeko(file_, static_cast<off_t>(position), SEEK_SET); #endif } diff --git a/third_party/libwebm/mkvparser/mkvparser.cc b/third_party/libwebm/mkvparser/mkvparser.cc index 21801154d..e62d6f607 100644 --- a/third_party/libwebm/mkvparser/mkvparser.cc +++ b/third_party/libwebm/mkvparser/mkvparser.cc @@ -25,6 +25,7 @@ namespace mkvparser { 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); } @@ -1475,6 +1476,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), @@ -1766,18 +1769,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; @@ -4125,7 +4117,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); @@ -5188,11 +5180,92 @@ 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::auto_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); + if (value_parse_status < 0) { + 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, @@ -5224,6 +5297,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; @@ -5274,6 +5348,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 @@ -5305,6 +5382,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 @@ -5405,6 +5483,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; } @@ -6698,8 +6778,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; diff --git a/third_party/libwebm/mkvparser/mkvparser.h b/third_party/libwebm/mkvparser/mkvparser.h index 42e6e88ab..26c2b7e5e 100644 --- a/third_party/libwebm/mkvparser/mkvparser.h +++ b/third_party/libwebm/mkvparser/mkvparser.h @@ -473,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&); @@ -497,6 +525,8 @@ class VideoTrack : public Track { Colour* GetColour() const; + Projection* GetProjection() const; + private: long long m_width; long long m_height; @@ -508,6 +538,7 @@ class VideoTrack : public Track { double m_rate; Colour* m_colour; + Projection* m_projection; }; class AudioTrack : public Track { @@ -813,6 +844,8 @@ class SeekHead { long Parse(); struct Entry { + Entry(); + // the SeekHead entry payload long long id; long long pos; diff --git a/third_party/libwebm/mkvparser/mkvreader.cc b/third_party/libwebm/mkvparser/mkvreader.cc index 9f90d8c4f..b8fd00c26 100644 --- a/third_party/libwebm/mkvparser/mkvreader.cc +++ b/third_party/libwebm/mkvparser/mkvreader.cc @@ -117,7 +117,7 @@ int MkvReader::Read(long long offset, long len, unsigned char* buffer) { if (status) return -1; // error #else - fseek(m_file, offset, SEEK_SET); + fseeko(m_file, static_cast<off_t>(offset), SEEK_SET); #endif const size_t size = fread(buffer, 1, len, m_file); @@ -128,4 +128,4 @@ int MkvReader::Read(long long offset, long len, unsigned char* buffer) { return 0; // success } -} // namespace mkvparser
\ No newline at end of file +} // namespace mkvparser |