]> granicus.if.org Git - libvpx/commitdiff
third_party: Roll libwebm snapshot.
authorTom Finegan <tomfinegan@google.com>
Thu, 24 Mar 2016 20:12:51 +0000 (13:12 -0700)
committerTom Finegan <tomfinegan@google.com>
Sat, 9 Apr 2016 05:01:48 +0000 (22:01 -0700)
32d5ac4 mkvmuxerutil: Fix MSVC build.
6397597 vpxpes_parser: Fix MSVC build.
784b6fe mkvmuxer: Revert changes to IMkvWriter types.
030518e webm_info: Fix implicit conversion warnings.
46d5dee sample_muxer: Fix implicit conversion warnings.
22b0845 webmts: Fix implicit conversion warnings.
ef464c2 mkvparser: Fix implicit conversion warnings.
0e9767e Merge "rename mingw64_toolchain.cmake to mingw-w64_toolchain"
f47cbd5 cmake: Move cxx flag testing/setup into its own file.
87443a6 rename mingw64_toolchain.cmake to mingw-w64_toolchain
2aee04f msvc_runtime.cmake: Check for MSVC, not WIN32.
eb50da8 Option to write timecode using fixed # of bytes
c1991fe mkvmuxer: Add missing Segment member initializer.
10aed96 Android.mk: Make libwebm easier to build downstream.
5c50e31 Add support for parsing VPx track codec private data.
4cbdbf1 Fix Android build.
bb48a3f mkvmuxerutil: remove stray 'int32'
a1cba34 Support cross compile for windows via mingw64.
596f5e0 Add webm_info.
ccf75f6 msvc/muxer_tests: Silence integer conversion warnings.
2ff2954 msvc/webm2pes: Silence integer and floating point conversion warnings.
1f24323 msvc/hdr_util: Silence double to float conversion warnings.
0744563 msvc/vpxpes_parser: Silence integer conversion warning.
59614b8 msvc/libwebm_util: Fix floating point to int conversion warning.
6481c24 webvtt: Fix include in vttreader.
e6ed0f4 msvc/vpxpes2ts: Fix MSVC integer conversion warning.
da64396 cmake/msvc: Disable C4996 project wide.
6ef8264 Merge "mkvparser::BlockEntry: inline EOS()"
3fa6aec mkvparser::BlockEntry: inline EOS()
26306f9 mkvmuxer: Remove unused Cluster ctor overload.
0d76597 mkvmuxer: Fix build with GCC 5.3.
0ba80bc mkvparser/sample: Minor clean up.
2e0e906 iosbuild.sh: Fix build.
918440a Makefile.unix: allow CXXFLAGS to be easily overridden
4ff5785 cmake: Add C++11 move ctor and member initializer tests.
402ef4d cmake: remove argc and argv from C++11 test main fns.
cbe5c40 Restore original namespaces for mkvmuxer and mkvparser.
504e0f2 Mass file extension update.
79cb980 Android.mk: Update source file locations.
01db4c2 webmids: Move to common/ sub dir.
235ce59 mkvparser: Explicitly reference internal sources in includes.
f578419 mkvmuxer: Move sources to mkvmuxer/ sub dir.
5f1065e webvtt: Organize and clean up webvtt support.
7abe8ac cmake: Add missing dumpvtt target.
f2f87e2 Makefile.unix: Tidy things up.
12f6dc3 Use <stdint.h> types instead of custom typedefs.
0407360 mkvmuxer: Write last block in each Cluster with Duration
008aa63 mkvparser: move to mkvparser sub dir.
e64bf75 Namespace reorg: Make everything a child of libwebm.
5fdb386 cmake: move c++11 checks into build/cxx11_tests.cmake.
3672488 Copy reference block values in Frame::CopyFrom()
91ca780 reapply clang-format
8d34215 Merge "Clean up AddAudioTrack in muxer_tests"
90861d4 Clean up AddAudioTrack in muxer_tests
a9dfb3d Un-ignore webm files in testdata
c5b76d8 Extract PES parser from WebM2Pes tests.
16524e8 cmake: Add include-what-you-use integration.
7015af5 iwyu/vpxpes2ts: Update includes.
c1d6a70 iwyu/webm2pes: Update includes.
110e797 iwyu/libwebm_util: Update includes.
44e31fb iwyu/webm2pes_tests: Update includes.
d919f96 iwyu/mkvwriter: Update includes.
75790e1 iwyu/mkvparser: Update includes.
5f673ca iwyu/webm2pes_main: Update includes.
747244a iwyu/vpxpes2ts_main: Update includes.
94c985f iwyu/mkvmuxerutil: Update includes.
c365630 iwyu/mkvmuxer: Update includes.
b15b8ef iwyu/file_util: Update includes.
3dfba95 iwyu/hdr_util: Update includes.
baba8b1 iwyu/vttdemux: Update includes.
3212ec1 iwyu/webvttparser: Update includes.
b6d8d92 iwyu/sample_muxer_metadata: Update includes.
a9a1a01 iwyu/sample_muxer: Update includes.
e020ffd iwyu/sample: Update includes.
18834bc iwyu/parser_tests: Update includes.
9c00ae3 iwyu/muxer_tests: Update includes.
41a17eb iwyu/test_util: Update includes
b6174be muxer_tests: Fix windows brokenness.
e092515 file_util: Remove tmpnam() usage in MSVC.
b9dc4ac test_util: Don't pass NULL to std::string() in GetTestDataDir().
1f74651 webmts: Move PES/TS sources to m2ts sub directory.
1b895e9 Rename libwebm_utils to libwebm_util.
2fabcd3 sample_muxer: Replace std::tmpnam() with libwebm::GetTempFileName().
e6a0033 Add file_util.
87f9bea Move hdr_util to common.
1f64aaf cmake: Expand C++11 tests.
6dc81c1 muxer_tests: Die immediately when unable to prep for file writing.
521ce4d webm2pes: Fix type limit warning.
64c4163 vpxpes2ts: Fix sign-compare and type-limits warnings.
741ba68 muxer_tests: Replace std::tmpnam() with GetTempFileName().
6159e83 Merge "test_util: add missing include for close()"
ff81c74 parser_tests: Fix sign compare warnings.
163f57d test_util: add missing include for close()
7c89eb5 Merge "test_util: Remove tmpnam() usage on non-MSVC targets."
c4b8686 Merge "webm2pes_tests: Fix sign compare warnings."
9c9f546 Merge "muxer_tests: Fix sign compare warnings."
0fbefef webm2pes: Silence sign compare warnings.
599e4e8 cmake: Silence clang/gcc deprecation warnings.
82f376f test_util: Remove tmpnam() usage on non-MSVC targets.
4d31d6b webm2pes_tests: Fix sign compare warnings.
07ed7e0 muxer_tests: Fix sign compare warnings.
ae2fbfe parser_tests: Silence sign compare warning.
f488528 libwebm_utils: Silence sign compare warning.
777247b Add C++11 detection to cmake file.
9b89187 Add missing include to libwebm_utils.h.
421874a Merge "mkvmuxer: Fix GCC build."
dd6ab35 Set the mastering metadata on the muxers colour
8b61ef5 mkvmuxer: Fix GCC build.
353b050 Add hdr_util.
c92e080 mkvmuxer: Use kValueNotPresent in Colour/MasteringMetadata.
2d09128 Colour element: TransferFunction renamed to TransferCharacteristics.
f2fc28e Colour element: Matrix renamed to MatrixCoefficients.
e0b1135 cmake: Minor CMakeLists.txt refactor.
1e1872b Revert change from auto_ptr to unique_ptr in sample code.
d7fc382 Track updates to the proposed Matroska Colour spec.
99981ee sample(mkvparser): Output Colour element when present.
375e416 mkvmuxer: Fix Colour element support.
eaeca34 mkvmuxer: Fix bits per channel in the colour element.
1dab7f3 mkvparser: Avoid crash when encountering a Colour element.
a1517aa sample_muxer: copy the Colour element.
ea9dd94 Merge "webm2pes: Fix tests."
8635c5b Merge "mkvparser: Make omitted values detectable in the Colour element."
ae4ae7e mkvparser: Make omitted values detectable in the Colour element.
8c8cba6 webm2pes: Fix tests.
a281a22 mkvmuxer: Add support for the Colour element and its children.
41a9147 sample_muxer: clang-format include order fix.
939a64d Signal E_BUFFER_NOT_FULL in EBMLHeader::Parse
fb1406e mkvparser: Add support for the Colour element and its children.
22bfdf7 Merge "parser_tests: Add validation of cues."
b873000 parser_tests: Add validation of cues.
799891e Update .gitignore to include some new binaries
e051c60 Merge "Update muxer test gold files"
b81d5f0 Update muxer test gold files
48b1e9a mkvparser: clang format run
93c4690 webm2pes: Add PES packet parsing tests.
65ca38f Merge "test_util: Fix gcc build."
520ca6c Merge "parser_tests: Fix gcc build."
37a38ca test_util: Fix gcc build.
ee0ebba parser_tests: Fix gcc build.
c32f970 Replace auto_ptr usage with unique_ptr.
e569ab0 webm2pes/ts: Fix gcc build.
2e55d6c Merge "add bitcode embedding support for ios"
0cfb2dc add bitcode embedding support for ios
bb8cefd webm2ts: Converts WebM VPx video to a MPEG TS.
453bf44 webm2pes: Begin addition of tests.
9299bbb libwebm: Googletest integration.
3bec1ba Merge changes I7bcb5b3e,I8ce733be,I98a928ff,I71910f24
5c83bbe Fix ParseElementHeader to support 0 payload elements
be35869 libwebm_utils: Add FileDeleter.
d6db1e1 webm2pes: Add a WebM parser init method.
aa3593e webm2pes: Rename Convert to ConvertToFile().
e8fca12 webm2pes: Fix super frame splitting.
3cb96b6 webm2pes: Move main() and helper functions into their own files.
021432b webm2pes: Fix the linux build.
82ac5fc Remove RELEASE.TXT.
852e173 webm2pes: Split super frames and packetize large frames.
faf85c2 webm2pes: Refactor header/optional header writing.
7c19266 Add Webm2Pes.
01fdee4 mkvmuxer: Disallow AddTrack() after Tracks element is output.
1ad314e mkvparser: EBMLHeader::Parse: remove dead init

Change-Id: I542bd5e34586f29d4d15771ec4bd728defe0769e

25 files changed:
examples.mk
libs.mk
test/test.mk
third_party/libwebm/Android.mk
third_party/libwebm/README.libvpx
third_party/libwebm/RELEASE.TXT [deleted file]
third_party/libwebm/common/file_util.cc [new file with mode: 0644]
third_party/libwebm/common/file_util.h [new file with mode: 0644]
third_party/libwebm/common/hdr_util.cc [new file with mode: 0644]
third_party/libwebm/common/hdr_util.h [new file with mode: 0644]
third_party/libwebm/common/webmids.h [moved from third_party/libwebm/webmids.hpp with 79% similarity]
third_party/libwebm/mkvmuxer/mkvmuxer.cc [moved from third_party/libwebm/mkvmuxer.cpp with 56% similarity]
third_party/libwebm/mkvmuxer/mkvmuxer.h [moved from third_party/libwebm/mkvmuxer.hpp with 68% similarity]
third_party/libwebm/mkvmuxer/mkvmuxertypes.h [moved from third_party/libwebm/mkvmuxertypes.hpp with 87% similarity]
third_party/libwebm/mkvmuxer/mkvmuxerutil.cc [moved from third_party/libwebm/mkvmuxerutil.cpp with 50% similarity]
third_party/libwebm/mkvmuxer/mkvmuxerutil.h [new file with mode: 0644]
third_party/libwebm/mkvmuxer/mkvwriter.cc [moved from third_party/libwebm/mkvwriter.cpp with 97% similarity]
third_party/libwebm/mkvmuxer/mkvwriter.h [moved from third_party/libwebm/mkvwriter.hpp with 87% similarity]
third_party/libwebm/mkvmuxerutil.hpp [deleted file]
third_party/libwebm/mkvparser/mkvparser.cc [moved from third_party/libwebm/mkvparser.cpp with 92% similarity]
third_party/libwebm/mkvparser/mkvparser.h [moved from third_party/libwebm/mkvparser.hpp with 90% similarity]
third_party/libwebm/mkvparser/mkvreader.cc [moved from third_party/libwebm/mkvreader.cpp with 97% similarity]
third_party/libwebm/mkvparser/mkvreader.h [moved from third_party/libwebm/mkvreader.hpp with 87% similarity]
webmdec.cc
webmenc.cc

index f10bec68c36f94bdb4afd93433ed3f560a992bf1..c891a5496227a86773b42e95487e670285077101 100644 (file)
@@ -36,21 +36,30 @@ LIBYUV_SRCS +=  third_party/libyuv/include/libyuv/basic_types.h  \
                 third_party/libyuv/source/scale_neon64.cc \
                 third_party/libyuv/source/scale_win.cc \
 
-LIBWEBM_COMMON_SRCS += third_party/libwebm/webmids.hpp
+LIBWEBM_COMMON_SRCS += third_party/libwebm/common/hdr_util.cc \
+                       third_party/libwebm/common/hdr_util.h \
+                       third_party/libwebm/common/webmids.h
 
-LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer.cpp \
-                      third_party/libwebm/mkvmuxerutil.cpp \
-                      third_party/libwebm/mkvwriter.cpp \
-                      third_party/libwebm/mkvmuxer.hpp \
-                      third_party/libwebm/mkvmuxertypes.hpp \
-                      third_party/libwebm/mkvmuxerutil.hpp \
-                      third_party/libwebm/mkvparser.hpp \
-                      third_party/libwebm/mkvwriter.hpp
+LIBWEBM_MUXER_SRCS += third_party/libwebm/mkvmuxer/mkvmuxer.cc \
+                      third_party/libwebm/mkvmuxer/mkvmuxerutil.cc \
+                      third_party/libwebm/mkvmuxer/mkvwriter.cc \
+                      third_party/libwebm/mkvmuxer/mkvmuxer.h \
+                      third_party/libwebm/mkvmuxer/mkvmuxertypes.h \
+                      third_party/libwebm/mkvmuxer/mkvmuxerutil.h \
+                      third_party/libwebm/mkvparser/mkvparser.h \
+                      third_party/libwebm/mkvmuxer/mkvwriter.h
+
+LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser/mkvparser.cc \
+                      third_party/libwebm/mkvparser/mkvreader.cc \
+                      third_party/libwebm/mkvparser/mkvparser.h \
+                      third_party/libwebm/mkvparser/mkvreader.h
+
+# Add compile flags and include path for libwebm sources.
+ifeq ($(CONFIG_WEBM_IO),yes)
+  CXXFLAGS     += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
+  INC_PATH-yes += $(SRC_PATH_BARE)/third_party/libwebm
+endif
 
-LIBWEBM_PARSER_SRCS = third_party/libwebm/mkvparser.cpp \
-                      third_party/libwebm/mkvreader.cpp \
-                      third_party/libwebm/mkvparser.hpp \
-                      third_party/libwebm/mkvreader.hpp
 
 # List of examples to build. UTILS are tools meant for distribution
 # while EXAMPLES demonstrate specific portions of the API.
@@ -70,6 +79,7 @@ ifeq ($(CONFIG_LIBYUV),yes)
 endif
 ifeq ($(CONFIG_WEBM_IO),yes)
   vpxdec.SRCS                 += $(LIBWEBM_COMMON_SRCS)
+  vpxdec.SRCS                 += $(LIBWEBM_MUXER_SRCS)
   vpxdec.SRCS                 += $(LIBWEBM_PARSER_SRCS)
   vpxdec.SRCS                 += webmdec.cc webmdec.h
 endif
@@ -93,6 +103,7 @@ endif
 ifeq ($(CONFIG_WEBM_IO),yes)
   vpxenc.SRCS                 += $(LIBWEBM_COMMON_SRCS)
   vpxenc.SRCS                 += $(LIBWEBM_MUXER_SRCS)
+  vpxenc.SRCS                 += $(LIBWEBM_PARSER_SRCS)
   vpxenc.SRCS                 += webmenc.cc webmenc.h
 endif
 vpxenc.GUID                  = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
diff --git a/libs.mk b/libs.mk
index e6fb068bf76d67cbeabeebea5c4953870560c5b5..c2a4725b053855b896ede8798e9d7de523170d0e 100644 (file)
--- a/libs.mk
+++ b/libs.mk
@@ -394,6 +394,12 @@ $(filter %$(ASM).o,$(OBJS-yes)): $(BUILD_PFX)vpx_config.asm
 $(shell $(SRC_PATH_BARE)/build/make/version.sh "$(SRC_PATH_BARE)" $(BUILD_PFX)vpx_version.h)
 CLEAN-OBJS += $(BUILD_PFX)vpx_version.h
 
+#
+# Add include path for libwebm sources.
+#
+ifeq ($(CONFIG_WEBM_IO),yes)
+  CXXFLAGS += -I$(SRC_PATH_BARE)/third_party/libwebm
+endif
 
 ##
 ## libvpx test directives
@@ -469,6 +475,7 @@ test_libvpx.$(VCPROJ_SFX): $(LIBVPX_TEST_SRCS) vpx.$(VCPROJ_SFX) gtest.$(VCPROJ_
             $(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
             --out=$@ $(INTERNAL_CFLAGS) $(CFLAGS) \
             -I. -I"$(SRC_PATH_BARE)/third_party/googletest/src/include" \
+            $(if $(CONFIG_WEBM_IO),-I"$(SRC_PATH_BARE)/third_party/libwebm") \
             -L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
 
 PROJECTS-$(CONFIG_MSVS) += test_libvpx.$(VCPROJ_SFX)
index 0a4b69ce043efb8518d11f55dac8c403237d975f..6931853623c8c249162f1e6da5b6d2360badc2e3 100644 (file)
@@ -59,10 +59,10 @@ LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS)    += y4m_test.cc ../y4menc.c ../y4menc.h
 
 ## WebM Parsing
 ifeq ($(CONFIG_WEBM_IO), yes)
-LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvparser.cpp
-LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvreader.cpp
-LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvparser.hpp
-LIBWEBM_PARSER_SRCS                    += ../third_party/libwebm/mkvreader.hpp
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.cc
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.cc
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvparser.h
+LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser/mkvreader.h
 LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += $(LIBWEBM_PARSER_SRCS)
 LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += ../tools_common.h
 LIBVPX_TEST_SRCS-$(CONFIG_DECODERS)    += ../webmdec.cc
index be9d77deed7ea9b718d52b0a820bb07d44883e5e..8149a083f4faa692719e8b48ff81f030f2b27da1 100644 (file)
@@ -2,9 +2,16 @@ LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE:= libwebm
-LOCAL_SRC_FILES:= mkvparser.cpp \
-                  mkvreader.cpp \
-                  mkvmuxer.cpp \
-                  mkvmuxerutil.cpp \
-                  mkvwriter.cpp
+LOCAL_CPPFLAGS:=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
+LOCAL_CPPFLAGS+=-D__STDC_LIMIT_MACROS -Wno-extern-c-compat
+LOCAL_C_INCLUDES:= $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)
+
+LOCAL_SRC_FILES:= common/file_util.cc \
+                  common/hdr_util.cc \
+                  mkvparser/mkvparser.cc \
+                  mkvparser/mkvreader.cc \
+                  mkvmuxer/mkvmuxer.cc \
+                  mkvmuxer/mkvmuxerutil.cc \
+                  mkvmuxer/mkvwriter.cc
 include $(BUILD_STATIC_LIBRARY)
index 2989d3d89a692d4a25fc273c96b1a276ddaae624..73f830322253da50a1852b508e42b4d0743e0398 100644 (file)
@@ -1,5 +1,5 @@
 URL: https://chromium.googlesource.com/webm/libwebm
-Version: 476366249e1fda7710a389cd41c57db42305e0d4
+Version: 32d5ac49414a8914ec1e1f285f3f927c6e8ec29d
 License: BSD
 License File: LICENSE.txt
 
diff --git a/third_party/libwebm/RELEASE.TXT b/third_party/libwebm/RELEASE.TXT
deleted file mode 100644 (file)
index a7e9f03..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-1.0.0.5\r
- * Handled case when no duration\r
- * Handled empty clusters\r
- * Handled empty clusters when seeking\r
- * Implemented check lacing bits\r
-\r
-1.0.0.4\r
- * Made Cues member variables mutables\r
- * Defined against badly-formatted cue points\r
- * Segment::GetCluster returns CuePoint too\r
- * Separated cue-based searches\r
-\r
-1.0.0.3\r
- * Added Block::GetOffset() to get a frame's offset in a block\r
- * Changed cluster count type from size_t to long\r
- * Parsed SeekHead to find cues\r
- * Allowed seeking beyond end of cluster cache\r
- * Added not to attempt to reparse cues element\r
- * Restructured Segment::LoadCluster\r
- * Marked position of cues without parsing cues element\r
- * Allowed cue points to be loaded incrementally\r
- * Implemented to load lazily cue points as they're searched\r
- * Merged Cues::LoadCuePoint into Cues::Find\r
- * Lazy init cues\r
- * Loaded cue point during find\r
-\r
-1.0.0.2\r
- * added support for Cues element\r
- * seeking was improved\r
-\r
-1.0.0.1\r
- * fixed item 141\r
- * added item 142\r
- * added this file, RELEASE.TXT, to repository\r
diff --git a/third_party/libwebm/common/file_util.cc b/third_party/libwebm/common/file_util.cc
new file mode 100644 (file)
index 0000000..4f91318
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+#include "common/file_util.h"
+
+#include <sys/stat.h>
+#ifndef _MSC_VER
+#include <unistd.h>  // close()
+#endif
+
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <ios>
+
+namespace libwebm {
+
+std::string GetTempFileName() {
+#if !defined _MSC_VER && !defined __MINGW32__
+  char temp_file_name_template[] = "libwebm_temp.XXXXXX";
+  int fd = mkstemp(temp_file_name_template);
+  if (fd != -1) {
+    close(fd);
+    return std::string(temp_file_name_template);
+  }
+  return std::string();
+#else
+  char tmp_file_name[_MAX_PATH];
+  errno_t err = tmpnam_s(tmp_file_name);
+  if (err == 0) {
+    return std::string(tmp_file_name);
+  }
+  return std::string();
+#endif
+}
+
+uint64_t GetFileSize(const std::string& file_name) {
+  uint64_t file_size = 0;
+#ifndef _MSC_VER
+  struct stat st;
+  st.st_size = 0;
+  if (stat(file_name.c_str(), &st) == 0) {
+#else
+  struct _stat st;
+  st.st_size = 0;
+  if (_stat(file_name.c_str(), &st) == 0) {
+#endif
+    file_size = st.st_size;
+  }
+  return file_size;
+}
+
+TempFileDeleter::TempFileDeleter() { file_name_ = GetTempFileName(); }
+
+TempFileDeleter::~TempFileDeleter() {
+  std::ifstream file(file_name_.c_str());
+  if (file.good()) {
+    file.close();
+    std::remove(file_name_.c_str());
+  }
+}
+
+}  // namespace libwebm
diff --git a/third_party/libwebm/common/file_util.h b/third_party/libwebm/common/file_util.h
new file mode 100644 (file)
index 0000000..0e71eac
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+#ifndef LIBWEBM_COMMON_FILE_UTIL_H_
+#define LIBWEBM_COMMON_FILE_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "mkvmuxer/mkvmuxertypes.h"  // LIBWEBM_DISALLOW_COPY_AND_ASSIGN()
+
+namespace libwebm {
+
+// Returns a temporary file name.
+std::string GetTempFileName();
+
+// Returns size of file specified by |file_name|, or 0 upon failure.
+uint64_t GetFileSize(const std::string& file_name);
+
+// Manages life of temporary file specified at time of construction. Deletes
+// file upon destruction.
+class TempFileDeleter {
+ public:
+  TempFileDeleter();
+  explicit TempFileDeleter(std::string file_name) : file_name_(file_name) {}
+  ~TempFileDeleter();
+  const std::string& name() const { return file_name_; }
+
+ private:
+  std::string file_name_;
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TempFileDeleter);
+};
+
+}  // namespace libwebm
+
+#endif  // LIBWEBM_COMMON_FILE_UTIL_H_
\ No newline at end of file
diff --git a/third_party/libwebm/common/hdr_util.cc b/third_party/libwebm/common/hdr_util.cc
new file mode 100644 (file)
index 0000000..e1a9842
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+#include "hdr_util.h"
+
+#include <cstddef>
+#include <new>
+
+#include "mkvparser/mkvparser.h"
+
+namespace libwebm {
+bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
+                             PrimaryChromaticityPtr* muxer_pc) {
+  muxer_pc->reset(new (std::nothrow)
+                      mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y));
+  if (!muxer_pc->get())
+    return false;
+  return true;
+}
+
+bool MasteringMetadataValuePresent(double value) {
+  return value != mkvparser::MasteringMetadata::kValueNotPresent;
+}
+
+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;
+  if (MasteringMetadataValuePresent(parser_mm.luminance_min))
+    muxer_mm->luminance_min = parser_mm.luminance_min;
+
+  PrimaryChromaticityPtr r_ptr(NULL);
+  PrimaryChromaticityPtr g_ptr(NULL);
+  PrimaryChromaticityPtr b_ptr(NULL);
+  PrimaryChromaticityPtr wp_ptr(NULL);
+
+  if (parser_mm.r) {
+    if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr))
+      return false;
+  }
+  if (parser_mm.g) {
+    if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr))
+      return false;
+  }
+  if (parser_mm.b) {
+    if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr))
+      return false;
+  }
+  if (parser_mm.white_point) {
+    if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr))
+      return false;
+  }
+
+  if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(),
+                                 wp_ptr.get())) {
+    return false;
+  }
+
+  return true;
+}
+
+bool ColourValuePresent(long long value) {
+  return value != mkvparser::Colour::kValueNotPresent;
+}
+
+bool CopyColour(const mkvparser::Colour& parser_colour,
+                mkvmuxer::Colour* muxer_colour) {
+  if (!muxer_colour)
+    return false;
+
+  if (ColourValuePresent(parser_colour.matrix_coefficients))
+    muxer_colour->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;
+  if (ColourValuePresent(parser_colour.cb_subsampling_horz))
+    muxer_colour->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;
+  if (ColourValuePresent(parser_colour.chroma_siting_horz))
+    muxer_colour->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;
+  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;
+  if (ColourValuePresent(parser_colour.primaries))
+    muxer_colour->primaries = parser_colour.primaries;
+  if (ColourValuePresent(parser_colour.max_cll))
+    muxer_colour->max_cll = parser_colour.max_cll;
+  if (ColourValuePresent(parser_colour.max_fall))
+    muxer_colour->max_fall = parser_colour.max_fall;
+
+  if (parser_colour.mastering_metadata) {
+    mkvmuxer::MasteringMetadata muxer_mm;
+    if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm))
+      return false;
+    if (!muxer_colour->SetMasteringMetadata(muxer_mm))
+      return false;
+  }
+  return true;
+}
+
+// Format of VPx private data:
+//
+//   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            |               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               |
+//  |                                                               |
+//  :               Bytes 1..Length of Codec Feature                :
+//  |                                                               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// ID Byte Format
+// ID byte is an unsigned byte.
+//   0 1 2 3 4 5 6 7
+//  +-+-+-+-+-+-+-+-+
+//  |X|    ID       |
+//  +-+-+-+-+-+-+-+-+
+//
+// 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};
+
+  for (int i = 0; i < kNumLevels; ++i) {
+    if (level == levels[i])
+      return level;
+  }
+
+  return 0;
+}
+}  // namespace libwebm
diff --git a/third_party/libwebm/common/hdr_util.h b/third_party/libwebm/common/hdr_util.h
new file mode 100644 (file)
index 0000000..d30c2b9
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (c) 2016 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+#ifndef LIBWEBM_COMMON_HDR_UTIL_H_
+#define LIBWEBM_COMMON_HDR_UTIL_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "mkvmuxer/mkvmuxer.h"
+
+namespace mkvparser {
+struct Colour;
+struct MasteringMetadata;
+struct PrimaryChromaticity;
+}  // namespace mkvparser
+
+namespace libwebm {
+// Utility types and functions for working with the Colour element and its
+// children. Copiers return true upon success. Presence functions return true
+// when the specified element is present.
+
+// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
+// required by libwebm.
+
+typedef std::auto_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
+
+bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
+                             PrimaryChromaticityPtr* muxer_pc);
+
+bool MasteringMetadataValuePresent(double value);
+
+bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
+                           mkvmuxer::MasteringMetadata* muxer_mm);
+
+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);
+
+}  // namespace libwebm
+
+#endif  // LIBWEBM_COMMON_HDR_UTIL_H_
similarity index 79%
rename from third_party/libwebm/webmids.hpp
rename to third_party/libwebm/common/webmids.h
index ad4ab5738894f577401d8ad5e0c815adb4d065c7..32a0c5fb9111d307867044d3b2ad37fba4015dec 100644 (file)
@@ -6,10 +6,10 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#ifndef WEBMIDS_HPP
-#define WEBMIDS_HPP
+#ifndef COMMON_WEBMIDS_H_
+#define COMMON_WEBMIDS_H_
 
-namespace mkvmuxer {
+namespace libwebm {
 
 enum MkvId {
   kMkvEBML = 0x1A45DFA3,
@@ -95,6 +95,35 @@ enum MkvId {
   kMkvAspectRatioType = 0x54B3,
   kMkvFrameRate = 0x2383E3,
   // end video
+  // colour
+  kMkvColour = 0x55B0,
+  kMkvMatrixCoefficients = 0x55B1,
+  kMkvBitsPerChannel = 0x55B2,
+  kMkvChromaSubsamplingHorz = 0x55B3,
+  kMkvChromaSubsamplingVert = 0x55B4,
+  kMkvCbSubsamplingHorz = 0x55B5,
+  kMkvCbSubsamplingVert = 0x55B6,
+  kMkvChromaSitingHorz = 0x55B7,
+  kMkvChromaSitingVert = 0x55B8,
+  kMkvRange = 0x55B9,
+  kMkvTransferCharacteristics = 0x55BA,
+  kMkvPrimaries = 0x55BB,
+  kMkvMaxCLL = 0x55BC,
+  kMkvMaxFALL = 0x55BD,
+  // mastering metadata
+  kMkvMasteringMetadata = 0x55D0,
+  kMkvPrimaryRChromaticityX = 0x55D1,
+  kMkvPrimaryRChromaticityY = 0x55D2,
+  kMkvPrimaryGChromaticityX = 0x55D3,
+  kMkvPrimaryGChromaticityY = 0x55D4,
+  kMkvPrimaryBChromaticityX = 0x55D5,
+  kMkvPrimaryBChromaticityY = 0x55D6,
+  kMkvWhitePointChromaticityX = 0x55D7,
+  kMkvWhitePointChromaticityY = 0x55D8,
+  kMkvLuminanceMax = 0x55D9,
+  kMkvLuminanceMin = 0x55DA,
+  // end mastering metadata
+  // end colour
   // audio
   kMkvAudio = 0xE1,
   kMkvSamplingFrequency = 0xB5,
@@ -150,6 +179,6 @@ enum MkvId {
   kMkvTagString = 0x4487
 };
 
-}  // end namespace mkvmuxer
+}  // namespace libwebm
 
-#endif  // WEBMIDS_HPP
+#endif  // COMMON_WEBMIDS_H_
similarity index 56%
rename from third_party/libwebm/mkvmuxer.cpp
rename to third_party/libwebm/mkvmuxer/mkvmuxer.cc
index 9be3119a4603311635058d3d1bd32da7a41ae913..c79ce24ed35d5d15497343d252ba2f4e6e185ef6 100644 (file)
@@ -6,27 +6,28 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#include "mkvmuxer.hpp"
+#include "mkvmuxer/mkvmuxer.h"
 
+#include <cfloat>
 #include <climits>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 #include <ctime>
+#include <memory>
 #include <new>
+#include <vector>
 
-#include "mkvmuxerutil.hpp"
-#include "mkvparser.hpp"
-#include "mkvwriter.hpp"
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxerutil.h"
+#include "mkvmuxer/mkvwriter.h"
+#include "mkvparser/mkvparser.h"
 
 namespace mkvmuxer {
 
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const uint64_t Colour::kValueNotPresent = UINT64_MAX;
+
 namespace {
 // Deallocate the string designated by |dst|, and then copy the |src|
 // string to |dst|.  The caller owns both the |src| string and the
@@ -55,6 +56,20 @@ bool StrCpy(const char* src, char** dst_ptr) {
   strcpy(dst, src);  // NOLINT
   return true;
 }
+
+typedef std::auto_ptr<PrimaryChromaticity> PrimaryChromaticityPtr;
+bool CopyChromaticity(const PrimaryChromaticity* src,
+                      PrimaryChromaticityPtr* dst) {
+  if (!dst)
+    return false;
+
+  dst->reset(new (std::nothrow) PrimaryChromaticity(src->x, src->y));
+  if (!dst->get())
+    return false;
+
+  return true;
+}
+
 }  // namespace
 
 ///////////////////////////////////////////////////////////////
@@ -65,31 +80,31 @@ IMkvWriter::IMkvWriter() {}
 
 IMkvWriter::~IMkvWriter() {}
 
-bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version) {
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) {
   // Level 0
-  uint64 size = EbmlElementSize(kMkvEBMLVersion, 1ULL);
-  size += EbmlElementSize(kMkvEBMLReadVersion, 1ULL);
-  size += EbmlElementSize(kMkvEBMLMaxIDLength, 4ULL);
-  size += EbmlElementSize(kMkvEBMLMaxSizeLength, 8ULL);
-  size += EbmlElementSize(kMkvDocType, "webm");
-  size += EbmlElementSize(kMkvDocTypeVersion, doc_type_version);
-  size += EbmlElementSize(kMkvDocTypeReadVersion, 2ULL);
+  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));
 
-  if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size))
     return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL))
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion, UINT64_C(1)))
     return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL))
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion, UINT64_C(1)))
     return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL))
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength, UINT64_C(4)))
     return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL))
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8)))
     return false;
-  if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocType, "webm"))
     return false;
-  if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion, doc_type_version))
     return false;
-  if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion, UINT64_C(2)))
     return false;
 
   return true;
@@ -100,16 +115,16 @@ bool WriteEbmlHeader(IMkvWriter* writer) {
 }
 
 bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
-                 mkvmuxer::int64 start, int64 size) {
+                 int64_t start, int64_t size) {
   // TODO(vigneshv): Check if this is a reasonable value.
-  const uint32 kBufSize = 2048;
-  uint8* buf = new uint8[kBufSize];
-  int64 offset = start;
+  const uint32_t kBufSize = 2048;
+  uint8_t* buf = new uint8_t[kBufSize];
+  int64_t offset = start;
   while (size > 0) {
-    const int64 read_len = (size > kBufSize) ? kBufSize : size;
+    const int64_t read_len = (size > kBufSize) ? kBufSize : size;
     if (source->Read(offset, static_cast<long>(read_len), buf))
       return false;
-    dst->Write(buf, static_cast<uint32>(read_len));
+    dst->Write(buf, static_cast<uint32_t>(read_len));
     offset += read_len;
     size -= read_len;
   }
@@ -126,6 +141,7 @@ Frame::Frame()
       additional_(NULL),
       additional_length_(0),
       duration_(0),
+      duration_set_(false),
       frame_(NULL),
       is_key_(false),
       length_(0),
@@ -158,16 +174,19 @@ bool Frame::CopyFrom(const Frame& frame) {
     return false;
   }
   duration_ = frame.duration();
+  duration_set_ = frame.duration_set();
   is_key_ = frame.is_key();
   track_number_ = frame.track_number();
   timestamp_ = frame.timestamp();
   discard_padding_ = frame.discard_padding();
+  reference_block_timestamp_ = frame.reference_block_timestamp();
+  reference_block_timestamp_set_ = frame.reference_block_timestamp_set();
   return true;
 }
 
-bool Frame::Init(const uint8* frame, uint64 length) {
-  uint8* const data =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
+bool Frame::Init(const uint8_t* frame, uint64_t length) {
+  uint8_t* const data =
+      new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
   if (!data)
     return false;
 
@@ -179,10 +198,10 @@ bool Frame::Init(const uint8* frame, uint64 length) {
   return true;
 }
 
-bool Frame::AddAdditionalData(const uint8* additional, uint64 length,
-                              uint64 add_id) {
-  uint8* const data =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
+bool Frame::AddAdditionalData(const uint8_t* additional, uint64_t length,
+                              uint64_t add_id) {
+  uint8_t* const data =
+      new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
   if (!data)
     return false;
 
@@ -216,7 +235,12 @@ bool Frame::CanBeSimpleBlock() const {
   return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
 }
 
-void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
+void Frame::set_duration(uint64_t duration) {
+  duration_ = duration;
+  duration_set_ = true;
+}
+
+void Frame::set_reference_block_timestamp(int64_t reference_block_timestamp) {
   reference_block_timestamp_ = reference_block_timestamp;
   reference_block_timestamp_set_ = true;
 }
@@ -238,61 +262,64 @@ bool CuePoint::Write(IMkvWriter* writer) const {
   if (!writer || track_ < 1 || cluster_pos_ < 1)
     return false;
 
-  uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
-  size += EbmlElementSize(kMkvCueTrack, track_);
+  uint64_t size =
+      EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_);
+  size += EbmlElementSize(libwebm::kMkvCueTrack, track_);
   if (output_block_number_ && block_number_ > 1)
-    size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
-  const uint64 track_pos_size =
-      EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
-  const uint64 payload_size =
-      EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
+    size += EbmlElementSize(libwebm::kMkvCueBlockNumber, 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;
 
-  if (!WriteEbmlMasterElement(writer, kMkvCuePoint, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvCuePoint, payload_size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvCueTime, time_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueTime, time_))
     return false;
 
-  if (!WriteEbmlMasterElement(writer, kMkvCueTrackPositions, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size))
     return false;
-  if (!WriteEbmlElement(writer, kMkvCueTrack, track_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack, track_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvCueClusterPosition, cluster_pos_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition, cluster_pos_))
     return false;
   if (output_block_number_ && block_number_ > 1)
-    if (!WriteEbmlElement(writer, kMkvCueBlockNumber, block_number_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber, block_number_))
       return false;
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0)
     return false;
 
-  if (stop_position - payload_position != static_cast<int64>(payload_size))
+  if (stop_position - payload_position != static_cast<int64_t>(payload_size))
     return false;
 
   return true;
 }
 
-uint64 CuePoint::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
-  size += EbmlElementSize(kMkvCueTrack, track_);
+uint64_t CuePoint::PayloadSize() const {
+  uint64_t size =
+      EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_);
+  size += EbmlElementSize(libwebm::kMkvCueTrack, track_);
   if (output_block_number_ && block_number_ > 1)
-    size += EbmlElementSize(kMkvCueBlockNumber, block_number_);
-  const uint64 track_pos_size =
-      EbmlMasterElementSize(kMkvCueTrackPositions, size) + size;
-  const uint64 payload_size =
-      EbmlElementSize(kMkvCueTime, time_) + track_pos_size;
+    size += EbmlElementSize(libwebm::kMkvCueBlockNumber, 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;
 
   return payload_size;
 }
 
-uint64 CuePoint::Size() const {
-  const uint64 payload_size = PayloadSize();
-  return EbmlMasterElementSize(kMkvCuePoint, payload_size) + payload_size;
+uint64_t CuePoint::Size() const {
+  const uint64_t payload_size = PayloadSize();
+  return EbmlMasterElementSize(libwebm::kMkvCuePoint, payload_size) +
+         payload_size;
 }
 
 ///////////////////////////////////////////////////////////////
@@ -307,7 +334,7 @@ Cues::Cues()
 
 Cues::~Cues() {
   if (cue_entries_) {
-    for (int32 i = 0; i < cue_entries_size_; ++i) {
+    for (int32_t i = 0; i < cue_entries_size_; ++i) {
       CuePoint* const cue = cue_entries_[i];
       delete cue;
     }
@@ -321,7 +348,7 @@ bool Cues::AddCue(CuePoint* cue) {
 
   if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
     // Add more CuePoints.
-    const int32 new_capacity =
+    const int32_t new_capacity =
         (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
 
     if (new_capacity < 1)
@@ -332,7 +359,7 @@ bool Cues::AddCue(CuePoint* cue) {
     if (!cues)
       return false;
 
-    for (int32 i = 0; i < cue_entries_size_; ++i) {
+    for (int32_t i = 0; i < cue_entries_size_; ++i) {
       cues[i] = cue_entries_[i];
     }
 
@@ -347,7 +374,7 @@ bool Cues::AddCue(CuePoint* cue) {
   return true;
 }
 
-CuePoint* Cues::GetCueByIndex(int32 index) const {
+CuePoint* Cues::GetCueByIndex(int32_t index) const {
   if (cue_entries_ == NULL)
     return NULL;
 
@@ -357,11 +384,11 @@ CuePoint* Cues::GetCueByIndex(int32 index) const {
   return cue_entries_[index];
 }
 
-uint64 Cues::Size() {
-  uint64 size = 0;
-  for (int32 i = 0; i < cue_entries_size_; ++i)
+uint64_t Cues::Size() {
+  uint64_t size = 0;
+  for (int32_t i = 0; i < cue_entries_size_; ++i)
     size += GetCueByIndex(i)->Size();
-  size += EbmlMasterElementSize(kMkvCues, size);
+  size += EbmlMasterElementSize(libwebm::kMkvCues, size);
   return size;
 }
 
@@ -369,8 +396,8 @@ bool Cues::Write(IMkvWriter* writer) const {
   if (!writer)
     return false;
 
-  uint64 size = 0;
-  for (int32 i = 0; i < cue_entries_size_; ++i) {
+  uint64_t size = 0;
+  for (int32_t i = 0; i < cue_entries_size_; ++i) {
     const CuePoint* const cue = GetCueByIndex(i);
 
     if (!cue)
@@ -379,25 +406,25 @@ bool Cues::Write(IMkvWriter* writer) const {
     size += cue->Size();
   }
 
-  if (!WriteEbmlMasterElement(writer, kMkvCues, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvCues, size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  for (int32 i = 0; i < cue_entries_size_; ++i) {
+  for (int32_t i = 0; i < cue_entries_size_; ++i) {
     const CuePoint* const cue = GetCueByIndex(i);
 
     if (!cue->Write(writer))
       return false;
   }
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0)
     return false;
 
-  if (stop_position - payload_position != static_cast<int64>(size))
+  if (stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
   return true;
@@ -409,36 +436,40 @@ bool Cues::Write(IMkvWriter* writer) const {
 
 ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
 
-uint64 ContentEncAESSettings::Size() const {
-  const uint64 payload = PayloadSize();
-  const uint64 size =
-      EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
+uint64_t ContentEncAESSettings::Size() const {
+  const uint64_t payload = PayloadSize();
+  const uint64_t size =
+      EbmlMasterElementSize(libwebm::kMkvContentEncAESSettings, payload) +
+      payload;
   return size;
 }
 
 bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
-  const uint64 payload = PayloadSize();
+  const uint64_t payload = PayloadSize();
 
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncAESSettings,
+                              payload))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode,
+                        cipher_mode_))
     return false;
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(payload))
+      stop_position - payload_position != static_cast<int64_t>(payload))
     return false;
 
   return true;
 }
 
-uint64 ContentEncAESSettings::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
+uint64_t ContentEncAESSettings::PayloadSize() const {
+  uint64_t size =
+      EbmlElementSize(libwebm::kMkvAESSettingsCipherMode, cipher_mode_);
   return size;
 }
 
@@ -456,14 +487,14 @@ ContentEncoding::ContentEncoding()
 
 ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
 
-bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
+bool ContentEncoding::SetEncryptionID(const uint8_t* id, uint64_t length) {
   if (!id || length < 1)
     return false;
 
   delete[] enc_key_id_;
 
   enc_key_id_ =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
+      new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
   if (!enc_key_id_)
     return false;
 
@@ -473,79 +504,89 @@ bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
   return true;
 }
 
-uint64 ContentEncoding::Size() const {
-  const uint64 encryption_size = EncryptionSize();
-  const uint64 encoding_size = EncodingSize(0, encryption_size);
-  const uint64 encodings_size =
-      EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
+uint64_t ContentEncoding::Size() const {
+  const uint64_t encryption_size = EncryptionSize();
+  const uint64_t encoding_size = EncodingSize(0, encryption_size);
+  const uint64_t encodings_size =
+      EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
+      encoding_size;
 
   return encodings_size;
 }
 
 bool ContentEncoding::Write(IMkvWriter* writer) const {
-  const uint64 encryption_size = EncryptionSize();
-  const uint64 encoding_size = EncodingSize(0, encryption_size);
-  const uint64 size =
-      EbmlMasterElementSize(kMkvContentEncoding, encoding_size) + encoding_size;
+  const uint64_t encryption_size = EncryptionSize();
+  const uint64_t encoding_size = EncodingSize(0, encryption_size);
+  const uint64_t size =
+      EbmlMasterElementSize(libwebm::kMkvContentEncoding, encoding_size) +
+      encoding_size;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncoding,
+                              encoding_size))
     return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder,
+                        encoding_order_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope,
+                        encoding_scope_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType,
+                        encoding_type_))
     return false;
 
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption,
+                              encryption_size))
     return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo, enc_algo_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncKeyID, enc_key_id_,
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_,
                         enc_key_id_length_))
     return false;
 
   if (!enc_aes_settings_.Write(writer))
     return false;
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
+      stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
   return true;
 }
 
-uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
-                                     uint64 encryption_size) const {
+uint64_t ContentEncoding::EncodingSize(uint64_t compresion_size,
+                                       uint64_t encryption_size) const {
   // TODO(fgalligan): Add support for compression settings.
   if (compresion_size != 0)
     return 0;
 
-  uint64 encoding_size = 0;
+  uint64_t encoding_size = 0;
 
   if (encryption_size > 0) {
     encoding_size +=
-        EbmlMasterElementSize(kMkvContentEncryption, encryption_size) +
+        EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) +
         encryption_size;
   }
-  encoding_size += EbmlElementSize(kMkvContentEncodingType, encoding_type_);
-  encoding_size += EbmlElementSize(kMkvContentEncodingScope, encoding_scope_);
-  encoding_size += EbmlElementSize(kMkvContentEncodingOrder, encoding_order_);
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingType, encoding_type_);
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingScope, encoding_scope_);
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingOrder, encoding_order_);
 
   return encoding_size;
 }
 
-uint64 ContentEncoding::EncryptionSize() const {
-  const uint64 aes_size = enc_aes_settings_.Size();
+uint64_t ContentEncoding::EncryptionSize() const {
+  const uint64_t aes_size = enc_aes_settings_.Size();
 
-  uint64 encryption_size =
-      EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_);
-  encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_);
+  uint64_t encryption_size = EbmlElementSize(libwebm::kMkvContentEncKeyID,
+                                             enc_key_id_, enc_key_id_length_);
+  encryption_size += EbmlElementSize(libwebm::kMkvContentEncAlgo, enc_algo_);
 
   return encryption_size + aes_size;
 }
@@ -577,7 +618,7 @@ Track::~Track() {
   delete[] name_;
 
   if (content_encoding_entries_) {
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
       ContentEncoding* const encoding = content_encoding_entries_[i];
       delete encoding;
     }
@@ -586,7 +627,7 @@ Track::~Track() {
 }
 
 bool Track::AddContentEncoding() {
-  const uint32 count = content_encoding_entries_size_ + 1;
+  const uint32_t count = content_encoding_entries_size_ + 1;
 
   ContentEncoding** const content_encoding_entries =
       new (std::nothrow) ContentEncoding*[count];  // NOLINT
@@ -600,7 +641,7 @@ bool Track::AddContentEncoding() {
     return false;
   }
 
-  for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
+  for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
     content_encoding_entries[i] = content_encoding_entries_[i];
   }
 
@@ -612,7 +653,7 @@ bool Track::AddContentEncoding() {
   return true;
 }
 
-ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
+ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const {
   if (content_encoding_entries_ == NULL)
     return NULL;
 
@@ -622,46 +663,47 @@ ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
   return content_encoding_entries_[index];
 }
 
-uint64 Track::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
-  size += EbmlElementSize(kMkvTrackUID, uid_);
-  size += EbmlElementSize(kMkvTrackType, type_);
+uint64_t Track::PayloadSize() const {
+  uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_);
+  size += EbmlElementSize(libwebm::kMkvTrackUID, uid_);
+  size += EbmlElementSize(libwebm::kMkvTrackType, type_);
   if (codec_id_)
-    size += EbmlElementSize(kMkvCodecID, codec_id_);
+    size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
   if (codec_private_)
-    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
+    size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
                             codec_private_length_);
   if (language_)
-    size += EbmlElementSize(kMkvLanguage, language_);
+    size += EbmlElementSize(libwebm::kMkvLanguage, language_);
   if (name_)
-    size += EbmlElementSize(kMkvName, name_);
+    size += EbmlElementSize(libwebm::kMkvName, name_);
   if (max_block_additional_id_)
-    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
+    size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+                            max_block_additional_id_);
   if (codec_delay_)
-    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
+    size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
   if (seek_pre_roll_)
-    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
+    size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
   if (default_duration_)
-    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
+    size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
 
   if (content_encoding_entries_size_ > 0) {
-    uint64 content_encodings_size = 0;
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
+    uint64_t content_encodings_size = 0;
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
       ContentEncoding* const encoding = content_encoding_entries_[i];
       content_encodings_size += encoding->Size();
     }
 
-    size +=
-        EbmlMasterElementSize(kMkvContentEncodings, content_encodings_size) +
-        content_encodings_size;
+    size += EbmlMasterElementSize(libwebm::kMkvContentEncodings,
+                                  content_encodings_size) +
+            content_encodings_size;
   }
 
   return size;
 }
 
-uint64 Track::Size() const {
-  uint64 size = PayloadSize();
-  size += EbmlMasterElementSize(kMkvTrackEntry, size);
+uint64_t Track::Size() const {
+  uint64_t size = PayloadSize();
+  size += EbmlMasterElementSize(libwebm::kMkvTrackEntry, size);
   return size;
 }
 
@@ -675,95 +717,97 @@ bool Track::Write(IMkvWriter* writer) const {
 
   // |size| may be bigger than what is written out in this function because
   // derived classes may write out more data in the Track element.
-  const uint64 payload_size = PayloadSize();
+  const uint64_t payload_size = PayloadSize();
 
-  if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size))
     return false;
 
-  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
-  size += EbmlElementSize(kMkvTrackUID, uid_);
-  size += EbmlElementSize(kMkvTrackType, type_);
+  uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_);
+  size += EbmlElementSize(libwebm::kMkvTrackUID, uid_);
+  size += EbmlElementSize(libwebm::kMkvTrackType, type_);
   if (codec_id_)
-    size += EbmlElementSize(kMkvCodecID, codec_id_);
+    size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
   if (codec_private_)
-    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
+    size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
                             codec_private_length_);
   if (language_)
-    size += EbmlElementSize(kMkvLanguage, language_);
+    size += EbmlElementSize(libwebm::kMkvLanguage, language_);
   if (name_)
-    size += EbmlElementSize(kMkvName, name_);
+    size += EbmlElementSize(libwebm::kMkvName, name_);
   if (max_block_additional_id_)
-    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
+    size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+                            max_block_additional_id_);
   if (codec_delay_)
-    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
+    size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
   if (seek_pre_roll_)
-    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
+    size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
   if (default_duration_)
-    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
+    size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvTrackNumber, number_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber, number_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvTrackUID, uid_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID, uid_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvTrackType, type_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackType, type_))
     return false;
   if (max_block_additional_id_) {
-    if (!WriteEbmlElement(writer, kMkvMaxBlockAdditionID,
+    if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID,
                           max_block_additional_id_)) {
       return false;
     }
   }
   if (codec_delay_) {
-    if (!WriteEbmlElement(writer, kMkvCodecDelay, codec_delay_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay, codec_delay_))
       return false;
   }
   if (seek_pre_roll_) {
-    if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll, seek_pre_roll_))
       return false;
   }
   if (default_duration_) {
-    if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration,
+                          default_duration_))
       return false;
   }
   if (codec_id_) {
-    if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecID, codec_id_))
       return false;
   }
   if (codec_private_) {
-    if (!WriteEbmlElement(writer, kMkvCodecPrivate, codec_private_,
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_,
                           codec_private_length_))
       return false;
   }
   if (language_) {
-    if (!WriteEbmlElement(writer, kMkvLanguage, language_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvLanguage, language_))
       return false;
   }
   if (name_) {
-    if (!WriteEbmlElement(writer, kMkvName, name_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvName, name_))
       return false;
   }
 
-  int64 stop_position = writer->Position();
+  int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
+      stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
   if (content_encoding_entries_size_ > 0) {
-    uint64 content_encodings_size = 0;
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
+    uint64_t content_encodings_size = 0;
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
       ContentEncoding* const encoding = content_encoding_entries_[i];
       content_encodings_size += encoding->Size();
     }
 
-    if (!WriteEbmlMasterElement(writer, kMkvContentEncodings,
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncodings,
                                 content_encodings_size))
       return false;
 
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
       ContentEncoding* const encoding = content_encoding_entries_[i];
       if (!encoding->Write(writer))
         return false;
@@ -776,14 +820,14 @@ bool Track::Write(IMkvWriter* writer) const {
   return true;
 }
 
-bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) {
+bool Track::SetCodecPrivate(const uint8_t* codec_private, uint64_t length) {
   if (!codec_private || length < 1)
     return false;
 
   delete[] codec_private_;
 
   codec_private_ =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
+      new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
   if (!codec_private_)
     return false;
 
@@ -842,6 +886,279 @@ void Track::set_name(const char* name) {
   }
 }
 
+///////////////////////////////////////////////////////////////
+//
+// Colour and its child elements
+
+uint64_t PrimaryChromaticity::PrimaryChromaticityPayloadSize(
+    libwebm::MkvId x_id, libwebm::MkvId y_id) const {
+  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);
+}
+
+uint64_t MasteringMetadata::MasteringMetadataSize() const {
+  uint64_t size = PayloadSize();
+
+  if (size > 0)
+    size += EbmlMasterElementSize(libwebm::kMkvMasteringMetadata, size);
+
+  return size;
+}
+
+bool MasteringMetadata::Write(IMkvWriter* writer) const {
+  const uint64_t size = PayloadSize();
+
+  // Don't write an empty element.
+  if (size == 0)
+    return true;
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvMasteringMetadata, size))
+    return false;
+  if (luminance_max != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvLuminanceMax, luminance_max)) {
+    return false;
+  }
+  if (luminance_min != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvLuminanceMin, luminance_min)) {
+    return false;
+  }
+  if (r_ &&
+      !r_->Write(writer, libwebm::kMkvPrimaryRChromaticityX,
+                 libwebm::kMkvPrimaryRChromaticityY)) {
+    return false;
+  }
+  if (g_ &&
+      !g_->Write(writer, libwebm::kMkvPrimaryGChromaticityX,
+                 libwebm::kMkvPrimaryGChromaticityY)) {
+    return false;
+  }
+  if (b_ &&
+      !b_->Write(writer, libwebm::kMkvPrimaryBChromaticityX,
+                 libwebm::kMkvPrimaryBChromaticityY)) {
+    return false;
+  }
+  if (white_point_ &&
+      !white_point_->Write(writer, libwebm::kMkvWhitePointChromaticityX,
+                           libwebm::kMkvWhitePointChromaticityY)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool MasteringMetadata::SetChromaticity(
+    const PrimaryChromaticity* r, const PrimaryChromaticity* g,
+    const PrimaryChromaticity* b, const PrimaryChromaticity* white_point) {
+  PrimaryChromaticityPtr r_ptr(NULL);
+  if (r) {
+    if (!CopyChromaticity(r, &r_ptr))
+      return false;
+  }
+  PrimaryChromaticityPtr g_ptr(NULL);
+  if (g) {
+    if (!CopyChromaticity(g, &g_ptr))
+      return false;
+  }
+  PrimaryChromaticityPtr b_ptr(NULL);
+  if (b) {
+    if (!CopyChromaticity(b, &b_ptr))
+      return false;
+  }
+  PrimaryChromaticityPtr wp_ptr(NULL);
+  if (white_point) {
+    if (!CopyChromaticity(white_point, &wp_ptr))
+      return false;
+  }
+
+  r_ = r_ptr.release();
+  g_ = g_ptr.release();
+  b_ = b_ptr.release();
+  white_point_ = wp_ptr.release();
+  return true;
+}
+
+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 (r_) {
+    size += r_->PrimaryChromaticityPayloadSize(
+        libwebm::kMkvPrimaryRChromaticityX, libwebm::kMkvPrimaryRChromaticityY);
+  }
+  if (g_) {
+    size += g_->PrimaryChromaticityPayloadSize(
+        libwebm::kMkvPrimaryGChromaticityX, libwebm::kMkvPrimaryGChromaticityY);
+  }
+  if (b_) {
+    size += b_->PrimaryChromaticityPayloadSize(
+        libwebm::kMkvPrimaryBChromaticityX, libwebm::kMkvPrimaryBChromaticityY);
+  }
+  if (white_point_) {
+    size += white_point_->PrimaryChromaticityPayloadSize(
+        libwebm::kMkvWhitePointChromaticityX,
+        libwebm::kMkvWhitePointChromaticityY);
+  }
+
+  return size;
+}
+
+uint64_t Colour::ColourSize() const {
+  uint64_t size = PayloadSize();
+
+  if (size > 0)
+    size += EbmlMasterElementSize(libwebm::kMkvColour, size);
+
+  return size;
+}
+
+bool Colour::Write(IMkvWriter* writer) const {
+  const uint64_t size = PayloadSize();
+
+  // Don't write an empty element.
+  if (size == 0)
+    return true;
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvColour, size))
+    return false;
+
+  if (matrix_coefficients != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvMatrixCoefficients,
+                        matrix_coefficients)) {
+    return false;
+  }
+  if (bits_per_channel != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvBitsPerChannel,
+                        bits_per_channel)) {
+    return false;
+  }
+  if (chroma_subsampling_horz != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingHorz,
+                        chroma_subsampling_horz)) {
+    return false;
+  }
+  if (chroma_subsampling_vert != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvChromaSubsamplingVert,
+                        chroma_subsampling_vert)) {
+    return false;
+  }
+
+  if (cb_subsampling_horz != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingHorz,
+                        cb_subsampling_horz)) {
+    return false;
+  }
+  if (cb_subsampling_vert != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvCbSubsamplingVert,
+                        cb_subsampling_vert)) {
+    return false;
+  }
+  if (chroma_siting_horz != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvChromaSitingHorz,
+                        chroma_siting_horz)) {
+    return false;
+  }
+  if (chroma_siting_vert != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvChromaSitingVert,
+                        chroma_siting_vert)) {
+    return false;
+  }
+  if (range != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvRange, range)) {
+    return false;
+  }
+  if (transfer_characteristics != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvTransferCharacteristics,
+                        transfer_characteristics)) {
+    return false;
+  }
+  if (primaries != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvPrimaries, primaries)) {
+    return false;
+  }
+  if (max_cll != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvMaxCLL, max_cll)) {
+    return false;
+  }
+  if (max_fall != kValueNotPresent &&
+      !WriteEbmlElement(writer, libwebm::kMkvMaxFALL, max_fall)) {
+    return false;
+  }
+
+  if (mastering_metadata_ && !mastering_metadata_->Write(writer))
+    return false;
+
+  return true;
+}
+
+bool Colour::SetMasteringMetadata(const MasteringMetadata& mastering_metadata) {
+  std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+  if (!mm_ptr.get())
+    return false;
+
+  mm_ptr->luminance_max = mastering_metadata.luminance_max;
+  mm_ptr->luminance_min = mastering_metadata.luminance_min;
+
+  if (!mm_ptr->SetChromaticity(mastering_metadata.r(), mastering_metadata.g(),
+                               mastering_metadata.b(),
+                               mastering_metadata.white_point())) {
+    return false;
+  }
+
+  delete mastering_metadata_;
+  mastering_metadata_ = mm_ptr.release();
+  return true;
+}
+
+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)
+    size += EbmlElementSize(libwebm::kMkvChromaSubsamplingHorz,
+                            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)
+    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);
+
+  if (mastering_metadata_)
+    size += mastering_metadata_->MasteringMetadataSize();
+
+  return size;
+}
+
 ///////////////////////////////////////////////////////////////
 //
 // VideoTrack Class
@@ -858,11 +1175,12 @@ VideoTrack::VideoTrack(unsigned int* seed)
       height_(0),
       stereo_mode_(0),
       alpha_mode_(0),
-      width_(0) {}
+      width_(0),
+      colour_(NULL) {}
 
-VideoTrack::~VideoTrack() {}
+VideoTrack::~VideoTrack() { delete colour_; }
 
-bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
+bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
   if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
       stereo_mode != kTopBottomRightIsFirst &&
       stereo_mode != kTopBottomLeftIsFirst &&
@@ -873,7 +1191,7 @@ bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
   return true;
 }
 
-bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
+bool VideoTrack::SetAlphaMode(uint64_t alpha_mode) {
   if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
     return false;
 
@@ -881,11 +1199,11 @@ bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
   return true;
 }
 
-uint64 VideoTrack::PayloadSize() const {
-  const uint64 parent_size = Track::PayloadSize();
+uint64_t VideoTrack::PayloadSize() const {
+  const uint64_t parent_size = Track::PayloadSize();
 
-  uint64 size = VideoPayloadSize();
-  size += EbmlMasterElementSize(kMkvVideo, size);
+  uint64_t size = VideoPayloadSize();
+  size += EbmlMasterElementSize(libwebm::kMkvVideo, size);
 
   return parent_size + size;
 }
@@ -894,88 +1212,122 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
   if (!Track::Write(writer))
     return false;
 
-  const uint64 size = VideoPayloadSize();
+  const uint64_t size = VideoPayloadSize();
 
-  if (!WriteEbmlMasterElement(writer, kMkvVideo, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvVideo, size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvPixelWidth, width_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvPixelWidth, width_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvPixelHeight, height_))
     return false;
   if (display_width_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth, display_width_))
       return false;
   }
   if (display_height_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight, display_height_))
       return false;
   }
   if (crop_left_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft, crop_left_))
       return false;
   }
   if (crop_right_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight, crop_right_))
       return false;
   }
   if (crop_top_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop, crop_top_))
       return false;
   }
   if (crop_bottom_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom, crop_bottom_))
       return false;
   }
   if (stereo_mode_ > kMono) {
-    if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode, stereo_mode_))
       return false;
   }
   if (alpha_mode_ > kNoAlpha) {
-    if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode, alpha_mode_))
       return false;
   }
   if (frame_rate_ > 0.0) {
-    if (!WriteEbmlElement(writer, kMkvFrameRate,
+    if (!WriteEbmlElement(writer, libwebm::kMkvFrameRate,
                           static_cast<float>(frame_rate_))) {
       return false;
     }
   }
+  if (colour_) {
+    if (!colour_->Write(writer))
+      return false;
+  }
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size)) {
+      stop_position - payload_position != static_cast<int64_t>(size)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool VideoTrack::SetColour(const Colour& colour) {
+  std::auto_ptr<Colour> colour_ptr(new Colour());
+  if (!colour_ptr.get())
     return false;
+
+  if (colour.mastering_metadata()) {
+    if (!colour_ptr->SetMasteringMetadata(*colour.mastering_metadata()))
+      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_ = colour_ptr.release();
   return true;
 }
 
-uint64 VideoTrack::VideoPayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
-  size += EbmlElementSize(kMkvPixelHeight, height_);
+uint64_t VideoTrack::VideoPayloadSize() const {
+  uint64_t size = EbmlElementSize(libwebm::kMkvPixelWidth, width_);
+  size += EbmlElementSize(libwebm::kMkvPixelHeight, height_);
   if (display_width_ > 0)
-    size += EbmlElementSize(kMkvDisplayWidth, display_width_);
+    size += EbmlElementSize(libwebm::kMkvDisplayWidth, display_width_);
   if (display_height_ > 0)
-    size += EbmlElementSize(kMkvDisplayHeight, display_height_);
+    size += EbmlElementSize(libwebm::kMkvDisplayHeight, display_height_);
   if (crop_left_ > 0)
-    size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
+    size += EbmlElementSize(libwebm::kMkvPixelCropLeft, crop_left_);
   if (crop_right_ > 0)
-    size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
+    size += EbmlElementSize(libwebm::kMkvPixelCropRight, crop_right_);
   if (crop_top_ > 0)
-    size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
+    size += EbmlElementSize(libwebm::kMkvPixelCropTop, crop_top_);
   if (crop_bottom_ > 0)
-    size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
+    size += EbmlElementSize(libwebm::kMkvPixelCropBottom, crop_bottom_);
   if (stereo_mode_ > kMono)
-    size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
+    size += EbmlElementSize(libwebm::kMkvStereoMode, stereo_mode_);
   if (alpha_mode_ > kNoAlpha)
-    size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
+    size += EbmlElementSize(libwebm::kMkvAlphaMode, alpha_mode_);
   if (frame_rate_ > 0.0)
-    size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
+    size += EbmlElementSize(libwebm::kMkvFrameRate,
+                            static_cast<float>(frame_rate_));
+  if (colour_)
+    size += colour_->ColourSize();
 
   return size;
 }
@@ -989,15 +1341,15 @@ AudioTrack::AudioTrack(unsigned int* seed)
 
 AudioTrack::~AudioTrack() {}
 
-uint64 AudioTrack::PayloadSize() const {
-  const uint64 parent_size = Track::PayloadSize();
+uint64_t AudioTrack::PayloadSize() const {
+  const uint64_t parent_size = Track::PayloadSize();
 
-  uint64 size =
-      EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
-  size += EbmlElementSize(kMkvChannels, channels_);
+  uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+                                  static_cast<float>(sample_rate_));
+  size += EbmlElementSize(libwebm::kMkvChannels, channels_);
   if (bit_depth_ > 0)
-    size += EbmlElementSize(kMkvBitDepth, bit_depth_);
-  size += EbmlMasterElementSize(kMkvAudio, size);
+    size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
+  size += EbmlMasterElementSize(libwebm::kMkvAudio, size);
 
   return parent_size + size;
 }
@@ -1007,31 +1359,31 @@ bool AudioTrack::Write(IMkvWriter* writer) const {
     return false;
 
   // Calculate AudioSettings size.
-  uint64 size =
-      EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
-  size += EbmlElementSize(kMkvChannels, channels_);
+  uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+                                  static_cast<float>(sample_rate_));
+  size += EbmlElementSize(libwebm::kMkvChannels, channels_);
   if (bit_depth_ > 0)
-    size += EbmlElementSize(kMkvBitDepth, bit_depth_);
+    size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
 
-  if (!WriteEbmlMasterElement(writer, kMkvAudio, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvSamplingFrequency,
+  if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency,
                         static_cast<float>(sample_rate_)))
     return false;
-  if (!WriteEbmlElement(writer, kMkvChannels, channels_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChannels, channels_))
     return false;
   if (bit_depth_ > 0)
-    if (!WriteEbmlElement(writer, kMkvBitDepth, bit_depth_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth, bit_depth_))
       return false;
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
+      stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
   return true;
@@ -1047,11 +1399,12 @@ const char Tracks::kVp8CodecId[] = "V_VP8";
 const char Tracks::kVp9CodecId[] = "V_VP9";
 const char Tracks::kVp10CodecId[] = "V_VP10";
 
-Tracks::Tracks() : track_entries_(NULL), track_entries_size_(0) {}
+Tracks::Tracks()
+    : track_entries_(NULL), track_entries_size_(0), wrote_tracks_(false) {}
 
 Tracks::~Tracks() {
   if (track_entries_) {
-    for (uint32 i = 0; i < track_entries_size_; ++i) {
+    for (uint32_t i = 0; i < track_entries_size_; ++i) {
       Track* const track = track_entries_[i];
       delete track;
     }
@@ -1059,8 +1412,8 @@ Tracks::~Tracks() {
   }
 }
 
-bool Tracks::AddTrack(Track* track, int32 number) {
-  if (number < 0)
+bool Tracks::AddTrack(Track* track, int32_t number) {
+  if (number < 0 || wrote_tracks_)
     return false;
 
   // This muxer only supports track numbers in the range [1, 126], in
@@ -1071,23 +1424,23 @@ bool Tracks::AddTrack(Track* track, int32 number) {
   if (number > 0x7E)
     return false;
 
-  uint32 track_num = number;
+  uint32_t track_num = number;
 
   if (track_num > 0) {
     // Check to make sure a track does not already have |track_num|.
-    for (uint32 i = 0; i < track_entries_size_; ++i) {
+    for (uint32_t i = 0; i < track_entries_size_; ++i) {
       if (track_entries_[i]->number() == track_num)
         return false;
     }
   }
 
-  const uint32 count = track_entries_size_ + 1;
+  const uint32_t count = track_entries_size_ + 1;
 
   Track** const track_entries = new (std::nothrow) Track*[count];  // NOLINT
   if (!track_entries)
     return false;
 
-  for (uint32 i = 0; i < track_entries_size_; ++i) {
+  for (uint32_t i = 0; i < track_entries_size_; ++i) {
     track_entries[i] = track_entries_[i];
   }
 
@@ -1101,7 +1454,7 @@ bool Tracks::AddTrack(Track* track, int32 number) {
     bool exit = false;
     do {
       exit = true;
-      for (uint32 i = 0; i < track_entries_size_; ++i) {
+      for (uint32_t i = 0; i < track_entries_size_; ++i) {
         if (track_entries[i]->number() == track_num) {
           track_num++;
           exit = false;
@@ -1118,7 +1471,7 @@ bool Tracks::AddTrack(Track* track, int32 number) {
   return true;
 }
 
-const Track* Tracks::GetTrackByIndex(uint32 index) const {
+const Track* Tracks::GetTrackByIndex(uint32_t index) const {
   if (track_entries_ == NULL)
     return NULL;
 
@@ -1128,9 +1481,9 @@ const Track* Tracks::GetTrackByIndex(uint32 index) const {
   return track_entries_[index];
 }
 
-Track* Tracks::GetTrackByNumber(uint64 track_number) const {
-  const int32 count = track_entries_size();
-  for (int32 i = 0; i < count; ++i) {
+Track* Tracks::GetTrackByNumber(uint64_t track_number) const {
+  const int32_t count = track_entries_size();
+  for (int32_t i = 0; i < count; ++i) {
     if (track_entries_[i]->number() == track_number)
       return track_entries_[i];
   }
@@ -1138,7 +1491,7 @@ Track* Tracks::GetTrackByNumber(uint64 track_number) const {
   return NULL;
 }
 
-bool Tracks::TrackIsAudio(uint64 track_number) const {
+bool Tracks::TrackIsAudio(uint64_t track_number) const {
   const Track* const track = GetTrackByNumber(track_number);
 
   if (track->type() == kAudio)
@@ -1147,7 +1500,7 @@ bool Tracks::TrackIsAudio(uint64 track_number) const {
   return false;
 }
 
-bool Tracks::TrackIsVideo(uint64 track_number) const {
+bool Tracks::TrackIsVideo(uint64_t track_number) const {
   const Track* const track = GetTrackByNumber(track_number);
 
   if (track->type() == kVideo)
@@ -1157,9 +1510,9 @@ bool Tracks::TrackIsVideo(uint64 track_number) const {
 }
 
 bool Tracks::Write(IMkvWriter* writer) const {
-  uint64 size = 0;
-  const int32 count = track_entries_size();
-  for (int32 i = 0; i < count; ++i) {
+  uint64_t size = 0;
+  const int32_t count = track_entries_size();
+  for (int32_t i = 0; i < count; ++i) {
     const Track* const track = GetTrackByIndex(i);
 
     if (!track)
@@ -1168,24 +1521,25 @@ bool Tracks::Write(IMkvWriter* writer) const {
     size += track->Size();
   }
 
-  if (!WriteEbmlMasterElement(writer, kMkvTracks, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTracks, size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  for (int32 i = 0; i < count; ++i) {
+  for (int32_t i = 0; i < count; ++i) {
     const Track* const track = GetTrackByIndex(i);
     if (!track->Write(writer))
       return false;
   }
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
+      stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
+  wrote_tracks_ = true;
   return true;
 }
 
@@ -1195,9 +1549,10 @@ bool Tracks::Write(IMkvWriter* writer) const {
 
 bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
 
-void Chapter::set_time(const Segment& segment, uint64 start_ns, uint64 end_ns) {
+void Chapter::set_time(const Segment& segment, uint64_t start_ns,
+                       uint64_t end_ns) {
   const SegmentInfo* const info = segment.GetSegmentInfo();
-  const uint64 timecode_scale = info->timecode_scale();
+  const uint64_t timecode_scale = info->timecode_scale();
   start_timecode_ = start_ns / timecode_scale;
   end_timecode_ = end_ns / timecode_scale;
 }
@@ -1292,38 +1647,40 @@ bool Chapter::ExpandDisplaysArray() {
   return true;
 }
 
-uint64 Chapter::WriteAtom(IMkvWriter* writer) const {
-  uint64 payload_size = EbmlElementSize(kMkvChapterStringUID, id_) +
-                        EbmlElementSize(kMkvChapterUID, uid_) +
-                        EbmlElementSize(kMkvChapterTimeStart, start_timecode_) +
-                        EbmlElementSize(kMkvChapterTimeEnd, end_timecode_);
+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_);
 
   for (int idx = 0; idx < displays_count_; ++idx) {
     const Display& d = displays_[idx];
     payload_size += d.WriteDisplay(NULL);
   }
 
-  const uint64 atom_size =
-      EbmlMasterElementSize(kMkvChapterAtom, payload_size) + payload_size;
+  const uint64_t atom_size =
+      EbmlMasterElementSize(libwebm::kMkvChapterAtom, payload_size) +
+      payload_size;
 
   if (writer == NULL)
     return atom_size;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
-  if (!WriteEbmlMasterElement(writer, kMkvChapterAtom, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterAtom, payload_size))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvChapterStringUID, id_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvChapterUID, uid_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID, uid_))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvChapterTimeStart, start_timecode_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart, start_timecode_))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvChapterTimeEnd, end_timecode_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd, end_timecode_))
     return 0;
 
   for (int idx = 0; idx < displays_count_; ++idx) {
@@ -1333,9 +1690,9 @@ uint64 Chapter::WriteAtom(IMkvWriter* writer) const {
       return 0;
   }
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != atom_size)
+  if (stop >= start && uint64_t(stop - start) != atom_size)
     return 0;
 
   return atom_size;
@@ -1365,42 +1722,44 @@ bool Chapter::Display::set_country(const char* country) {
   return StrCpy(country, &country_);
 }
 
-uint64 Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
-  uint64 payload_size = EbmlElementSize(kMkvChapString, title_);
+uint64_t Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
+  uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapString, title_);
 
   if (language_)
-    payload_size += EbmlElementSize(kMkvChapLanguage, language_);
+    payload_size += EbmlElementSize(libwebm::kMkvChapLanguage, language_);
 
   if (country_)
-    payload_size += EbmlElementSize(kMkvChapCountry, country_);
+    payload_size += EbmlElementSize(libwebm::kMkvChapCountry, country_);
 
-  const uint64 display_size =
-      EbmlMasterElementSize(kMkvChapterDisplay, payload_size) + payload_size;
+  const uint64_t display_size =
+      EbmlMasterElementSize(libwebm::kMkvChapterDisplay, payload_size) +
+      payload_size;
 
   if (writer == NULL)
     return display_size;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
-  if (!WriteEbmlMasterElement(writer, kMkvChapterDisplay, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterDisplay,
+                              payload_size))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvChapString, title_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapString, title_))
     return 0;
 
   if (language_) {
-    if (!WriteEbmlElement(writer, kMkvChapLanguage, language_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvChapLanguage, language_))
       return 0;
   }
 
   if (country_) {
-    if (!WriteEbmlElement(writer, kMkvChapCountry, country_))
+    if (!WriteEbmlElement(writer, libwebm::kMkvChapCountry, country_))
       return 0;
   }
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != display_size)
+  if (stop >= start && uint64_t(stop - start) != display_size)
     return 0;
 
   return display_size;
@@ -1438,19 +1797,19 @@ bool Chapters::Write(IMkvWriter* writer) const {
   if (writer == NULL)
     return false;
 
-  const uint64 payload_size = WriteEdition(NULL);  // return size only
+  const uint64_t payload_size = WriteEdition(NULL);  // return size only
 
-  if (!WriteEbmlMasterElement(writer, kMkvChapters, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapters, payload_size))
     return false;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
   if (WriteEdition(writer) == 0)  // error
     return false;
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != payload_size)
+  if (stop >= start && uint64_t(stop - start) != payload_size)
     return false;
 
   return true;
@@ -1480,36 +1839,37 @@ bool Chapters::ExpandChaptersArray() {
   return true;
 }
 
-uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
-  uint64 payload_size = 0;
+uint64_t Chapters::WriteEdition(IMkvWriter* writer) const {
+  uint64_t payload_size = 0;
 
   for (int idx = 0; idx < chapters_count_; ++idx) {
     const Chapter& chapter = chapters_[idx];
     payload_size += chapter.WriteAtom(NULL);
   }
 
-  const uint64 edition_size =
-      EbmlMasterElementSize(kMkvEditionEntry, payload_size) + payload_size;
+  const uint64_t edition_size =
+      EbmlMasterElementSize(libwebm::kMkvEditionEntry, payload_size) +
+      payload_size;
 
   if (writer == NULL)  // return size only
     return edition_size;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
-  if (!WriteEbmlMasterElement(writer, kMkvEditionEntry, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvEditionEntry, payload_size))
     return 0;  // error
 
   for (int idx = 0; idx < chapters_count_; ++idx) {
     const Chapter& chapter = chapters_[idx];
 
-    const uint64 chapter_size = chapter.WriteAtom(writer);
+    const uint64_t chapter_size = chapter.WriteAtom(writer);
     if (chapter_size == 0)  // error
       return 0;
   }
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != edition_size)
+  if (stop >= start && uint64_t(stop - start) != edition_size)
     return 0;
 
   return edition_size;
@@ -1581,23 +1941,23 @@ bool Tag::ExpandSimpleTagsArray() {
   return true;
 }
 
-uint64 Tag::Write(IMkvWriter* writer) const {
-  uint64 payload_size = 0;
+uint64_t Tag::Write(IMkvWriter* writer) const {
+  uint64_t payload_size = 0;
 
   for (int idx = 0; idx < simple_tags_count_; ++idx) {
     const SimpleTag& st = simple_tags_[idx];
     payload_size += st.Write(NULL);
   }
 
-  const uint64 tag_size =
-      EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
+  const uint64_t tag_size =
+      EbmlMasterElementSize(libwebm::kMkvTag, payload_size) + payload_size;
 
   if (writer == NULL)
     return tag_size;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
-  if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTag, payload_size))
     return 0;
 
   for (int idx = 0; idx < simple_tags_count_; ++idx) {
@@ -1607,9 +1967,9 @@ uint64 Tag::Write(IMkvWriter* writer) const {
       return 0;
   }
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != tag_size)
+  if (stop >= start && uint64_t(stop - start) != tag_size)
     return 0;
 
   return tag_size;
@@ -1635,31 +1995,32 @@ bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
   return StrCpy(tag_string, &tag_string_);
 }
 
-uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
-  uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
+uint64_t Tag::SimpleTag::Write(IMkvWriter* writer) const {
+  uint64_t payload_size = EbmlElementSize(libwebm::kMkvTagName, tag_name_);
 
-  payload_size += EbmlElementSize(kMkvTagString, tag_string_);
+  payload_size += EbmlElementSize(libwebm::kMkvTagString, tag_string_);
 
-  const uint64 simple_tag_size =
-      EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
+  const uint64_t simple_tag_size =
+      EbmlMasterElementSize(libwebm::kMkvSimpleTag, payload_size) +
+      payload_size;
 
   if (writer == NULL)
     return simple_tag_size;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
-  if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvSimpleTag, payload_size))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTagName, tag_name_))
     return 0;
 
-  if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTagString, tag_string_))
     return 0;
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != simple_tag_size)
+  if (stop >= start && uint64_t(stop - start) != simple_tag_size)
     return 0;
 
   return simple_tag_size;
@@ -1694,29 +2055,29 @@ bool Tags::Write(IMkvWriter* writer) const {
   if (writer == NULL)
     return false;
 
-  uint64 payload_size = 0;
+  uint64_t payload_size = 0;
 
   for (int idx = 0; idx < tags_count_; ++idx) {
     const Tag& tag = tags_[idx];
     payload_size += tag.Write(NULL);
   }
 
-  if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTags, payload_size))
     return false;
 
-  const int64 start = writer->Position();
+  const int64_t start = writer->Position();
 
   for (int idx = 0; idx < tags_count_; ++idx) {
     const Tag& tag = tags_[idx];
 
-    const uint64 tag_size = tag.Write(writer);
+    const uint64_t tag_size = tag.Write(writer);
     if (tag_size == 0)  // error
       return 0;
   }
 
-  const int64 stop = writer->Position();
+  const int64_t stop = writer->Position();
 
-  if (stop >= start && uint64(stop - start) != payload_size)
+  if (stop >= start && uint64_t(stop - start) != payload_size)
     return false;
 
   return true;
@@ -1750,15 +2111,18 @@ bool Tags::ExpandTagsArray() {
 //
 // Cluster class
 
-Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
+Cluster::Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
+                 bool write_last_frame_with_duration, bool fixed_size_timecode)
     : blocks_added_(0),
       finalized_(false),
+      fixed_size_timecode_(fixed_size_timecode),
       header_written_(false),
       payload_size_(0),
       position_for_cues_(cues_pos),
       size_position_(-1),
       timecode_(timecode),
       timecode_scale_(timecode_scale),
+      write_last_frame_with_duration_(write_last_frame_with_duration),
       writer_(NULL) {}
 
 Cluster::~Cluster() {}
@@ -1771,24 +2135,27 @@ bool Cluster::Init(IMkvWriter* ptr_writer) {
   return true;
 }
 
-bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
+bool Cluster::AddFrame(const Frame* const frame) {
+  return QueueOrWriteFrame(frame);
+}
 
-bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                       uint64 abs_timecode, bool is_key) {
+bool Cluster::AddFrame(const uint8_t* data, uint64_t length,
+                       uint64_t track_number, uint64_t abs_timecode,
+                       bool is_key) {
   Frame frame;
   if (!frame.Init(data, length))
     return false;
   frame.set_track_number(track_number);
   frame.set_timestamp(abs_timecode);
   frame.set_is_key(is_key);
-  return DoWriteFrame(&frame);
+  return QueueOrWriteFrame(&frame);
 }
 
-bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
-                                     const uint8* additional,
-                                     uint64 additional_length, uint64 add_id,
-                                     uint64 track_number, uint64 abs_timecode,
-                                     bool is_key) {
+bool Cluster::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+                                     const uint8_t* additional,
+                                     uint64_t additional_length,
+                                     uint64_t add_id, uint64_t track_number,
+                                     uint64_t abs_timecode, bool is_key) {
   if (!additional || additional_length == 0) {
     return false;
   }
@@ -1800,13 +2167,13 @@ bool Cluster::AddFrameWithAdditional(const uint8* data, uint64 length,
   frame.set_track_number(track_number);
   frame.set_timestamp(abs_timecode);
   frame.set_is_key(is_key);
-  return DoWriteFrame(&frame);
+  return QueueOrWriteFrame(&frame);
 }
 
-bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                         int64 discard_padding,
-                                         uint64 track_number,
-                                         uint64 abs_timecode, bool is_key) {
+bool Cluster::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+                                         int64_t discard_padding,
+                                         uint64_t track_number,
+                                         uint64_t abs_timecode, bool is_key) {
   Frame frame;
   if (!frame.Init(data, length))
     return false;
@@ -1814,11 +2181,12 @@ bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
   frame.set_track_number(track_number);
   frame.set_timestamp(abs_timecode);
   frame.set_is_key(is_key);
-  return DoWriteFrame(&frame);
+  return QueueOrWriteFrame(&frame);
 }
 
-bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                          uint64 abs_timecode, uint64 duration_timecode) {
+bool Cluster::AddMetadata(const uint8_t* data, uint64_t length,
+                          uint64_t track_number, uint64_t abs_timecode,
+                          uint64_t duration_timecode) {
   Frame frame;
   if (!frame.Init(data, length))
     return false;
@@ -1826,17 +2194,62 @@ bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
   frame.set_timestamp(abs_timecode);
   frame.set_duration(duration_timecode);
   frame.set_is_key(true);  // All metadata blocks are keyframes.
-  return DoWriteFrame(&frame);
+  return QueueOrWriteFrame(&frame);
 }
 
-void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
+void Cluster::AddPayloadSize(uint64_t size) { payload_size_ += size; }
 
 bool Cluster::Finalize() {
-  if (!writer_ || finalized_ || size_position_ == -1)
+  return !write_last_frame_with_duration_ && Finalize(false, 0);
+}
+
+bool Cluster::Finalize(bool set_last_frame_duration, uint64_t duration) {
+  if (!writer_ || finalized_)
+    return false;
+
+  if (write_last_frame_with_duration_) {
+    // Write out held back Frames. This essentially performs a k-way merge
+    // across all tracks in the increasing order of timestamps.
+    while (!stored_frames_.empty()) {
+      Frame* frame = stored_frames_.begin()->second.front();
+
+      // Get the next frame to write (frame with least timestamp across all
+      // tracks).
+      for (FrameMapIterator frames_iterator = ++stored_frames_.begin();
+           frames_iterator != stored_frames_.end(); ++frames_iterator) {
+        if (frames_iterator->second.front()->timestamp() < frame->timestamp()) {
+          frame = frames_iterator->second.front();
+        }
+      }
+
+      // Set the duration if it's the last frame for the track.
+      if (set_last_frame_duration &&
+          stored_frames_[frame->track_number()].size() == 1 &&
+          !frame->duration_set()) {
+        frame->set_duration(duration - frame->timestamp());
+        if (!frame->is_key() && !frame->reference_block_timestamp_set()) {
+          frame->set_reference_block_timestamp(
+              last_block_timestamp_[frame->track_number()]);
+        }
+      }
+
+      // Write the frame and remove it from |stored_frames_|.
+      const bool wrote_frame = DoWriteFrame(frame);
+      stored_frames_[frame->track_number()].pop_front();
+      if (stored_frames_[frame->track_number()].empty()) {
+        stored_frames_.erase(frame->track_number());
+      }
+      delete frame;
+      if (!wrote_frame)
+        return false;
+    }
+  }
+
+  if (size_position_ == -1)
     return false;
 
   if (writer_->Seekable()) {
-    const int64 pos = writer_->Position();
+    const int64_t pos = writer_->Position();
 
     if (writer_->Position(size_position_))
       return false;
@@ -1853,9 +2266,10 @@ bool Cluster::Finalize() {
   return true;
 }
 
-uint64 Cluster::Size() const {
-  const uint64 element_size =
-      EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
+uint64_t Cluster::Size() const {
+  const uint64_t element_size =
+      EbmlMasterElementSize(libwebm::kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) +
+      payload_size_;
   return element_size;
 }
 
@@ -1871,15 +2285,15 @@ bool Cluster::PreWriteBlock() {
   return true;
 }
 
-void Cluster::PostWriteBlock(uint64 element_size) {
+void Cluster::PostWriteBlock(uint64_t element_size) {
   AddPayloadSize(element_size);
   ++blocks_added_;
 }
 
-int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
-  const int64 cluster_timecode = this->Cluster::timecode();
-  const int64 rel_timecode =
-      static_cast<int64>(abs_timecode) - cluster_timecode;
+int64_t Cluster::GetRelativeTimecode(int64_t abs_timecode) const {
+  const int64_t cluster_timecode = this->Cluster::timecode();
+  const int64_t rel_timecode =
+      static_cast<int64_t>(abs_timecode) - cluster_timecode;
 
   if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
     return -1;
@@ -1894,11 +2308,67 @@ bool Cluster::DoWriteFrame(const Frame* const frame) {
   if (!PreWriteBlock())
     return false;
 
-  const uint64 element_size = WriteFrame(writer_, frame, this);
+  const uint64_t element_size = WriteFrame(writer_, frame, this);
   if (element_size == 0)
     return false;
 
   PostWriteBlock(element_size);
+  last_block_timestamp_[frame->track_number()] = frame->timestamp();
+  return true;
+}
+
+bool Cluster::QueueOrWriteFrame(const Frame* const frame) {
+  if (!frame || !frame->IsValid())
+    return false;
+
+  // If |write_last_frame_with_duration_| is not set, then write the frame right
+  // away.
+  if (!write_last_frame_with_duration_) {
+    return DoWriteFrame(frame);
+  }
+
+  // Queue the current frame.
+  uint64_t track_number = frame->track_number();
+  Frame* const frame_to_store = new Frame();
+  frame_to_store->CopyFrom(*frame);
+  stored_frames_[track_number].push_back(frame_to_store);
+
+  // Iterate through all queued frames in the current track except the last one
+  // and write it if it is okay to do so (i.e.) no other track has an held back
+  // frame with timestamp <= the timestamp of the frame in question.
+  std::vector<std::list<Frame*>::iterator> frames_to_erase;
+  for (std::list<Frame *>::iterator
+           current_track_iterator = stored_frames_[track_number].begin(),
+           end = --stored_frames_[track_number].end();
+       current_track_iterator != end; ++current_track_iterator) {
+    const Frame* const frame_to_write = *current_track_iterator;
+    bool okay_to_write = true;
+    for (FrameMapIterator track_iterator = stored_frames_.begin();
+         track_iterator != stored_frames_.end(); ++track_iterator) {
+      if (track_iterator->first == track_number) {
+        continue;
+      }
+      if (track_iterator->second.front()->timestamp() <
+          frame_to_write->timestamp()) {
+        okay_to_write = false;
+        break;
+      }
+    }
+    if (okay_to_write) {
+      const bool wrote_frame = DoWriteFrame(frame_to_write);
+      delete frame_to_write;
+      if (!wrote_frame)
+        return false;
+      frames_to_erase.push_back(current_track_iterator);
+    } else {
+      break;
+    }
+  }
+  for (std::vector<std::list<Frame*>::iterator>::iterator iterator =
+           frames_to_erase.begin();
+       iterator != frames_to_erase.end(); ++iterator) {
+    stored_frames_[track_number].erase(*iterator);
+  }
   return true;
 }
 
@@ -1906,7 +2376,7 @@ bool Cluster::WriteClusterHeader() {
   if (finalized_)
     return false;
 
-  if (WriteID(writer_, kMkvCluster))
+  if (WriteID(writer_, libwebm::kMkvCluster))
     return false;
 
   // Save for later.
@@ -1917,9 +2387,12 @@ bool Cluster::WriteClusterHeader() {
   if (SerializeInt(writer_, kEbmlUnknownValue, 8))
     return false;
 
-  if (!WriteEbmlElement(writer_, kMkvTimecode, timecode()))
+  if (!WriteEbmlElement(writer_, libwebm::kMkvTimecode, timecode(),
+                        fixed_size_timecode_ ? 8 : 0)) {
     return false;
-  AddPayloadSize(EbmlElementSize(kMkvTimecode, timecode()));
+  }
+  AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode(),
+                                 fixed_size_timecode_ ? 8 : 0));
   header_written_ = true;
 
   return true;
@@ -1930,7 +2403,7 @@ bool Cluster::WriteClusterHeader() {
 // SeekHead Class
 
 SeekHead::SeekHead() : start_pos_(0ULL) {
-  for (int32 i = 0; i < kSeekEntryCount; ++i) {
+  for (int32_t i = 0; i < kSeekEntryCount; ++i) {
     seek_entry_id_[i] = 0;
     seek_entry_pos_[i] = 0;
   }
@@ -1943,17 +2416,19 @@ bool SeekHead::Finalize(IMkvWriter* writer) const {
     if (start_pos_ == -1)
       return false;
 
-    uint64 payload_size = 0;
-    uint64 entry_size[kSeekEntryCount];
+    uint64_t payload_size = 0;
+    uint64_t entry_size[kSeekEntryCount];
 
-    for (int32 i = 0; i < kSeekEntryCount; ++i) {
+    for (int32_t i = 0; i < kSeekEntryCount; ++i) {
       if (seek_entry_id_[i] != 0) {
-        entry_size[i] =
-            EbmlElementSize(kMkvSeekID, static_cast<uint64>(seek_entry_id_[i]));
-        entry_size[i] += EbmlElementSize(kMkvSeekPosition, seek_entry_pos_[i]);
+        entry_size[i] = EbmlElementSize(
+            libwebm::kMkvSeekID, static_cast<uint64_t>(seek_entry_id_[i]));
+        entry_size[i] +=
+            EbmlElementSize(libwebm::kMkvSeekPosition, seek_entry_pos_[i]);
 
         payload_size +=
-            EbmlMasterElementSize(kMkvSeek, entry_size[i]) + entry_size[i];
+            EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) +
+            entry_size[i];
       }
     }
 
@@ -1961,34 +2436,35 @@ bool SeekHead::Finalize(IMkvWriter* writer) const {
     if (payload_size == 0)
       return true;
 
-    const int64 pos = writer->Position();
+    const int64_t pos = writer->Position();
     if (writer->Position(start_pos_))
       return false;
 
-    if (!WriteEbmlMasterElement(writer, kMkvSeekHead, payload_size))
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeekHead, payload_size))
       return false;
 
-    for (int32 i = 0; i < kSeekEntryCount; ++i) {
+    for (int32_t i = 0; i < kSeekEntryCount; ++i) {
       if (seek_entry_id_[i] != 0) {
-        if (!WriteEbmlMasterElement(writer, kMkvSeek, entry_size[i]))
+        if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeek, entry_size[i]))
           return false;
 
-        if (!WriteEbmlElement(writer, kMkvSeekID,
-                              static_cast<uint64>(seek_entry_id_[i])))
+        if (!WriteEbmlElement(writer, libwebm::kMkvSeekID,
+                              static_cast<uint64_t>(seek_entry_id_[i])))
           return false;
 
-        if (!WriteEbmlElement(writer, kMkvSeekPosition, seek_entry_pos_[i]))
+        if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition,
+                              seek_entry_pos_[i]))
           return false;
       }
     }
 
-    const uint64 total_entry_size = kSeekEntryCount * MaxEntrySize();
-    const uint64 total_size =
-        EbmlMasterElementSize(kMkvSeekHead, total_entry_size) +
+    const uint64_t total_entry_size = kSeekEntryCount * MaxEntrySize();
+    const uint64_t total_size =
+        EbmlMasterElementSize(libwebm::kMkvSeekHead, total_entry_size) +
         total_entry_size;
-    const int64 size_left = total_size - (writer->Position() - start_pos_);
+    const int64_t size_left = total_size - (writer->Position() - start_pos_);
 
-    const uint64 bytes_written = WriteVoidElement(writer, size_left);
+    const uint64_t bytes_written = WriteVoidElement(writer, size_left);
     if (!bytes_written)
       return false;
 
@@ -2000,20 +2476,21 @@ bool SeekHead::Finalize(IMkvWriter* writer) const {
 }
 
 bool SeekHead::Write(IMkvWriter* writer) {
-  const uint64 entry_size = kSeekEntryCount * MaxEntrySize();
-  const uint64 size = EbmlMasterElementSize(kMkvSeekHead, entry_size);
+  const uint64_t entry_size = kSeekEntryCount * MaxEntrySize();
+  const uint64_t size =
+      EbmlMasterElementSize(libwebm::kMkvSeekHead, entry_size);
 
   start_pos_ = writer->Position();
 
-  const uint64 bytes_written = WriteVoidElement(writer, size + entry_size);
+  const uint64_t bytes_written = WriteVoidElement(writer, size + entry_size);
   if (!bytes_written)
     return false;
 
   return true;
 }
 
-bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
-  for (int32 i = 0; i < kSeekEntryCount; ++i) {
+bool SeekHead::AddSeekEntry(uint32_t id, uint64_t pos) {
+  for (int32_t i = 0; i < kSeekEntryCount; ++i) {
     if (seek_entry_id_[i] == 0) {
       seek_entry_id_[i] = id;
       seek_entry_pos_[i] = pos;
@@ -2023,19 +2500,19 @@ bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
   return false;
 }
 
-uint32 SeekHead::GetId(int index) const {
+uint32_t SeekHead::GetId(int index) const {
   if (index < 0 || index >= kSeekEntryCount)
     return UINT_MAX;
   return seek_entry_id_[index];
 }
 
-uint64 SeekHead::GetPosition(int index) const {
+uint64_t SeekHead::GetPosition(int index) const {
   if (index < 0 || index >= kSeekEntryCount)
     return ULLONG_MAX;
   return seek_entry_pos_[index];
 }
 
-bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
+bool SeekHead::SetSeekEntry(int index, uint32_t id, uint64_t position) {
   if (index < 0 || index >= kSeekEntryCount)
     return false;
   seek_entry_id_[index] = id;
@@ -2043,12 +2520,12 @@ bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
   return true;
 }
 
-uint64 SeekHead::MaxEntrySize() const {
-  const uint64 max_entry_payload_size =
-      EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
-      EbmlElementSize(kMkvSeekPosition, 0xffffffffffffffffULL);
-  const uint64 max_entry_size =
-      EbmlMasterElementSize(kMkvSeek, max_entry_payload_size) +
+uint64_t SeekHead::MaxEntrySize() const {
+  const uint64_t max_entry_payload_size =
+      EbmlElementSize(libwebm::kMkvSeekID, UINT64_C(0xffffffff)) +
+      EbmlElementSize(libwebm::kMkvSeekPosition, UINT64_C(0xffffffffffffffff));
+  const uint64_t max_entry_size =
+      EbmlMasterElementSize(libwebm::kMkvSeek, max_entry_payload_size) +
       max_entry_payload_size;
 
   return max_entry_size;
@@ -2072,10 +2549,10 @@ SegmentInfo::~SegmentInfo() {
 }
 
 bool SegmentInfo::Init() {
-  int32 major;
-  int32 minor;
-  int32 build;
-  int32 revision;
+  int32_t major;
+  int32_t minor;
+  int32_t build;
+  int32_t revision;
   GetVersion(&major, &minor, &build, &revision);
   char temp[256];
 #ifdef _MSC_VER
@@ -2115,12 +2592,12 @@ bool SegmentInfo::Finalize(IMkvWriter* writer) const {
       if (duration_pos_ == -1)
         return false;
 
-      const int64 pos = writer->Position();
+      const int64_t pos = writer->Position();
 
       if (writer->Position(duration_pos_))
         return false;
 
-      if (!WriteEbmlElement(writer, kMkvDuration,
+      if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
                             static_cast<float>(duration_)))
         return false;
 
@@ -2136,43 +2613,45 @@ bool SegmentInfo::Write(IMkvWriter* writer) {
   if (!writer || !muxing_app_ || !writing_app_)
     return false;
 
-  uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_);
+  uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale, timecode_scale_);
   if (duration_ > 0.0)
-    size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
+    size +=
+        EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_));
   if (date_utc_ != LLONG_MIN)
-    size += EbmlDateElementSize(kMkvDateUTC);
-  size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
-  size += EbmlElementSize(kMkvWritingApp, writing_app_);
+    size += EbmlDateElementSize(libwebm::kMkvDateUTC);
+  size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_);
+  size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_);
 
-  if (!WriteEbmlMasterElement(writer, kMkvInfo, size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvInfo, size))
     return false;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return false;
 
-  if (!WriteEbmlElement(writer, kMkvTimecodeScale, timecode_scale_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale, timecode_scale_))
     return false;
 
   if (duration_ > 0.0) {
     // Save for later
     duration_pos_ = writer->Position();
 
-    if (!WriteEbmlElement(writer, kMkvDuration, static_cast<float>(duration_)))
+    if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
+                          static_cast<float>(duration_)))
       return false;
   }
 
   if (date_utc_ != LLONG_MIN)
-    WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_);
+    WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_);
 
-  if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_))
     return false;
-  if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_))
+  if (!WriteEbmlElement(writer, libwebm::kMkvWritingApp, writing_app_))
     return false;
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
+      stop_position - payload_position != static_cast<int64_t>(size))
     return false;
 
   return true;
@@ -2244,6 +2723,8 @@ Segment::Segment()
       mode_(kFile),
       new_cuepoint_(false),
       output_cues_(true),
+      accurate_cluster_duration_(false),
+      fixed_size_cluster_timecode_(false),
       payload_pos_(0),
       size_position_(0),
       doc_type_version_(kDefaultDocTypeVersion),
@@ -2260,7 +2741,7 @@ Segment::Segment()
 
 Segment::~Segment() {
   if (cluster_list_) {
-    for (int32 i = 0; i < cluster_list_size_; ++i) {
+    for (int32_t i = 0; i < cluster_list_size_; ++i) {
       Cluster* const cluster = cluster_list_[i];
       delete cluster;
     }
@@ -2268,7 +2749,7 @@ Segment::~Segment() {
   }
 
   if (frames_) {
-    for (int32 i = 0; i < frames_size_; ++i) {
+    for (int32_t i = 0; i < frames_size_; ++i) {
       Frame* const frame = frames_[i];
       delete frame;
     }
@@ -2292,13 +2773,13 @@ Segment::~Segment() {
   }
 }
 
-void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
-                                           uint64* cues_size) {
+void Segment::MoveCuesBeforeClustersHelper(uint64_t diff, int32_t index,
+                                           uint64_t* cues_size) {
   CuePoint* const cue_point = cues_.GetCueByIndex(index);
   if (cue_point == NULL)
     return;
-  const uint64 old_cue_point_size = cue_point->Size();
-  const uint64 cluster_pos = cue_point->cluster_pos() + diff;
+  const uint64_t old_cue_point_size = cue_point->Size();
+  const uint64_t cluster_pos = cue_point->cluster_pos() + diff;
   cue_point->set_cluster_pos(cluster_pos);  // update the new cluster position
   // New size of the cue is computed as follows
   //    Let a = current sum of size of all CuePoints
@@ -2308,40 +2789,40 @@ void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
   //    Let d = b + c. Now d is the |diff| passed to the next recursive call.
   //    Let e = a + b. Now e is the |cues_size| passed to the next recursive
   //                   call.
-  const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
-  const uint64 cue_size_diff =
+  const uint64_t cue_point_size_diff = cue_point->Size() - old_cue_point_size;
+  const uint64_t cue_size_diff =
       GetCodedUIntSize(*cues_size + cue_point_size_diff) -
       GetCodedUIntSize(*cues_size);
   *cues_size += cue_point_size_diff;
   diff = cue_size_diff + cue_point_size_diff;
   if (diff > 0) {
-    for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
+    for (int32_t i = 0; i < cues_.cue_entries_size(); ++i) {
       MoveCuesBeforeClustersHelper(diff, i, cues_size);
     }
   }
 }
 
 void Segment::MoveCuesBeforeClusters() {
-  const uint64 current_cue_size = cues_.Size();
-  uint64 cue_size = 0;
-  for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
+  const uint64_t current_cue_size = cues_.Size();
+  uint64_t cue_size = 0;
+  for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
     cue_size += cues_.GetCueByIndex(i)->Size();
-  for (int32 i = 0; i < cues_.cue_entries_size(); ++i)
+  for (int32_t i = 0; i < cues_.cue_entries_size(); ++i)
     MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
 
   // Adjust the Seek Entry to reflect the change in position
   // of Cluster and Cues
-  int32 cluster_index = 0;
-  int32 cues_index = 0;
-  for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) {
-    if (seek_head_.GetId(i) == kMkvCluster)
+  int32_t cluster_index = 0;
+  int32_t cues_index = 0;
+  for (int32_t i = 0; i < SeekHead::kSeekEntryCount; ++i) {
+    if (seek_head_.GetId(i) == libwebm::kMkvCluster)
       cluster_index = i;
-    if (seek_head_.GetId(i) == kMkvCues)
+    if (seek_head_.GetId(i) == libwebm::kMkvCues)
       cues_index = i;
   }
-  seek_head_.SetSeekEntry(cues_index, kMkvCues,
+  seek_head_.SetSeekEntry(cues_index, libwebm::kMkvCues,
                           seek_head_.GetPosition(cluster_index));
-  seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
+  seek_head_.SetSeekEntry(cluster_index, libwebm::kMkvCluster,
                           cues_.Size() + seek_head_.GetPosition(cues_index));
 }
 
@@ -2359,8 +2840,8 @@ bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
                                             IMkvWriter* writer) {
   if (!writer->Seekable() || chunking_)
     return false;
-  const int64 cluster_offset =
-      cluster_list_[0]->size_position() - GetUIntSize(kMkvCluster);
+  const int64_t cluster_offset =
+      cluster_list_[0]->size_position() - GetUIntSize(libwebm::kMkvCluster);
 
   // Copy the headers.
   if (!ChunkedCopy(reader, writer, 0, cluster_offset))
@@ -2383,8 +2864,8 @@ bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
     return false;
 
   // Update the Segment size in case the Cues size has changed.
-  const int64 pos = writer->Position();
-  const int64 segment_size = writer->Position() - payload_pos_;
+  const int64_t pos = writer->Position();
+  const int64_t segment_size = writer->Position() - payload_pos_;
   if (writer->Position(size_position_) ||
       WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
     return false;
@@ -2395,15 +2876,17 @@ bool Segment::Finalize() {
   if (WriteFramesAll() < 0)
     return false;
 
-  if (mode_ == kFile) {
-    if (cluster_list_size_ > 0) {
-      // Update last cluster's size
-      Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
+  if (cluster_list_size_ > 0) {
+    // Update last cluster's size
+    Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
 
-      if (!old_cluster || !old_cluster->Finalize())
-        return false;
-    }
+    // For the last frame of the last Cluster, we don't write it as a BlockGroup
+    // with Duration unless the frame itself has duration set explicitly.
+    if (!old_cluster || !old_cluster->Finalize(false, 0))
+      return false;
+  }
 
+  if (mode_ == kFile) {
     if (chunking_ && chunk_writer_cluster_) {
       chunk_writer_cluster_->Close();
       chunk_count_++;
@@ -2417,7 +2900,7 @@ bool Segment::Finalize() {
       return false;
 
     if (output_cues_)
-      if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
+      if (!seek_head_.AddSeekEntry(libwebm::kMkvCues, MaxOffset()))
         return false;
 
     if (chunking_) {
@@ -2448,11 +2931,11 @@ bool Segment::Finalize() {
       if (size_position_ == -1)
         return false;
 
-      const int64 segment_size = MaxOffset();
+      const int64_t segment_size = MaxOffset();
       if (segment_size < 1)
         return false;
 
-      const int64 pos = writer_header_->Position();
+      const int64_t pos = writer_header_->Position();
       UpdateDocTypeVersion();
       if (doc_type_version_ != doc_type_version_written_) {
         if (writer_header_->Position(0))
@@ -2490,7 +2973,7 @@ bool Segment::Finalize() {
   return true;
 }
 
-Track* Segment::AddTrack(int32 number) {
+Track* Segment::AddTrack(int32_t number) {
   Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
 
   if (!track)
@@ -2508,7 +2991,7 @@ Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
 
 Tag* Segment::AddTag() { return tags_.AddTag(); }
 
-uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
+uint64_t Segment::AddVideoTrack(int32_t width, int32_t height, int32_t number) {
   VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_);  // NOLINT
   if (!track)
     return 0;
@@ -2524,7 +3007,7 @@ uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
   return track->number();
 }
 
-bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
+bool Segment::AddCuePoint(uint64_t timestamp, uint64_t track) {
   if (cluster_list_size_ < 1)
     return false;
 
@@ -2547,7 +3030,8 @@ bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
   return true;
 }
 
-uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
+uint64_t Segment::AddAudioTrack(int32_t sample_rate, int32_t channels,
+                                int32_t number) {
   AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_);  // NOLINT
   if (!track)
     return 0;
@@ -2562,8 +3046,8 @@ uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
   return track->number();
 }
 
-bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                       uint64 timestamp, bool is_key) {
+bool Segment::AddFrame(const uint8_t* data, uint64_t length,
+                       uint64_t track_number, uint64_t timestamp, bool is_key) {
   if (!data)
     return false;
 
@@ -2576,11 +3060,11 @@ bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
   return AddGenericFrame(&frame);
 }
 
-bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
-                                     const uint8* additional,
-                                     uint64 additional_length, uint64 add_id,
-                                     uint64 track_number, uint64 timestamp,
-                                     bool is_key) {
+bool Segment::AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+                                     const uint8_t* additional,
+                                     uint64_t additional_length,
+                                     uint64_t add_id, uint64_t track_number,
+                                     uint64_t timestamp, bool is_key) {
   if (!data || !additional)
     return false;
 
@@ -2595,10 +3079,10 @@ bool Segment::AddFrameWithAdditional(const uint8* data, uint64 length,
   return AddGenericFrame(&frame);
 }
 
-bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                         int64 discard_padding,
-                                         uint64 track_number, uint64 timestamp,
-                                         bool is_key) {
+bool Segment::AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+                                         int64_t discard_padding,
+                                         uint64_t track_number,
+                                         uint64_t timestamp, bool is_key) {
   if (!data)
     return false;
 
@@ -2612,8 +3096,9 @@ bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
   return AddGenericFrame(&frame);
 }
 
-bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                          uint64 timestamp_ns, uint64 duration_ns) {
+bool Segment::AddMetadata(const uint8_t* data, uint64_t length,
+                          uint64_t track_number, uint64_t timestamp_ns,
+                          uint64_t duration_ns) {
   if (!data)
     return false;
 
@@ -2702,6 +3187,14 @@ bool Segment::AddGenericFrame(const Frame* frame) {
 
 void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
 
+void Segment::AccurateClusterDuration(bool accurate_cluster_duration) {
+  accurate_cluster_duration_ = accurate_cluster_duration;
+}
+
+void Segment::UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode) {
+  fixed_size_cluster_timecode_ = fixed_size_cluster_timecode;
+}
+
 bool Segment::SetChunking(bool chunking, const char* filename) {
   if (chunk_count_ > 0)
     return false;
@@ -2781,7 +3274,7 @@ bool Segment::SetChunking(bool chunking, const char* filename) {
   return true;
 }
 
-bool Segment::CuesTrack(uint64 track_number) {
+bool Segment::CuesTrack(uint64_t track_number) {
   const Track* const track = GetTrackByNumber(track_number);
   if (!track)
     return false;
@@ -2792,7 +3285,7 @@ bool Segment::CuesTrack(uint64 track_number) {
 
 void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
 
-Track* Segment::GetTrackByNumber(uint64 track_number) const {
+Track* Segment::GetTrackByNumber(uint64_t track_number) const {
   return tracks_.GetTrackByNumber(track_number);
 }
 
@@ -2803,11 +3296,11 @@ bool Segment::WriteSegmentHeader() {
   if (!WriteEbmlHeader(writer_header_, doc_type_version_))
     return false;
   doc_type_version_written_ = doc_type_version_;
-  ebml_header_size_ = static_cast<int32>(writer_header_->Position());
+  ebml_header_size_ = static_cast<int32_t>(writer_header_->Position());
 
   // Write "unknown" (-1) as segment size value. If mode is kFile, Segment
   // will write over duration when the file is finalized.
-  if (WriteID(writer_header_, kMkvSegment))
+  if (WriteID(writer_header_, libwebm::kMkvSegment))
     return false;
 
   // Save for later.
@@ -2831,25 +3324,25 @@ bool Segment::WriteSegmentHeader() {
       return false;
   }
 
-  if (!seek_head_.AddSeekEntry(kMkvInfo, MaxOffset()))
+  if (!seek_head_.AddSeekEntry(libwebm::kMkvInfo, MaxOffset()))
     return false;
   if (!segment_info_.Write(writer_header_))
     return false;
 
-  if (!seek_head_.AddSeekEntry(kMkvTracks, MaxOffset()))
+  if (!seek_head_.AddSeekEntry(libwebm::kMkvTracks, MaxOffset()))
     return false;
   if (!tracks_.Write(writer_header_))
     return false;
 
   if (chapters_.Count() > 0) {
-    if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset()))
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvChapters, MaxOffset()))
       return false;
     if (!chapters_.Write(writer_header_))
       return false;
   }
 
   if (tags_.Count() > 0) {
-    if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvTags, MaxOffset()))
       return false;
     if (!tags_.Write(writer_header_))
       return false;
@@ -2870,7 +3363,7 @@ bool Segment::WriteSegmentHeader() {
 // Here we are testing whether to create a new cluster, given a frame
 // having time frame_timestamp_ns.
 //
-int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
+int Segment::TestFrame(uint64_t track_number, uint64_t frame_timestamp_ns,
                        bool is_key) const {
   if (force_new_cluster_)
     return 1;
@@ -2888,11 +3381,11 @@ int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
   // written to the existing cluster, or that a new cluster should be
   // created.
 
-  const uint64 timecode_scale = segment_info_.timecode_scale();
-  const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
+  const uint64_t timecode_scale = segment_info_.timecode_scale();
+  const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
 
   const Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
-  const uint64 last_cluster_timecode = last_cluster->timecode();
+  const uint64_t last_cluster_timecode = last_cluster->timecode();
 
   // For completeness we test for the case when the frame's timecode
   // is less than the cluster's timecode.  Although in principle that
@@ -2907,7 +3400,7 @@ int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
   // using a 16-bit signed integer), then we cannot write this frame
   // to that cluster, and so we must create a new cluster.
 
-  const int64 delta_timecode = frame_timecode - last_cluster_timecode;
+  const int64_t delta_timecode = frame_timecode - last_cluster_timecode;
 
   if (delta_timecode > kMaxBlockTimecode)
     return 2;
@@ -2923,7 +3416,7 @@ int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
   // already, where "too many" is defined as "the total time of frames
   // in the cluster exceeds a threshold".
 
-  const uint64 delta_ns = delta_timecode * timecode_scale;
+  const uint64_t delta_ns = delta_timecode * timecode_scale;
 
   if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
     return 1;
@@ -2932,7 +3425,7 @@ int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
   // cluster is created when the size of the current cluster exceeds a
   // threshold.
 
-  const uint64 cluster_size = last_cluster->payload_size();
+  const uint64_t cluster_size = last_cluster->payload_size();
 
   if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
     return 1;
@@ -2942,19 +3435,19 @@ int Segment::TestFrame(uint64 track_number, uint64 frame_timestamp_ns,
   return 0;
 }
 
-bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
-  const int32 new_size = cluster_list_size_ + 1;
+bool Segment::MakeNewCluster(uint64_t frame_timestamp_ns) {
+  const int32_t new_size = cluster_list_size_ + 1;
 
   if (new_size > cluster_list_capacity_) {
     // Add more clusters.
-    const int32 new_capacity =
+    const int32_t new_capacity =
         (cluster_list_capacity_ <= 0) ? 1 : cluster_list_capacity_ * 2;
     Cluster** const clusters =
         new (std::nothrow) Cluster*[new_capacity];  // NOLINT
     if (!clusters)
       return false;
 
-    for (int32 i = 0; i < cluster_list_size_; ++i) {
+    for (int32_t i = 0; i < cluster_list_size_; ++i) {
       clusters[i] = cluster_list_[i];
     }
 
@@ -2967,19 +3460,17 @@ bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
   if (!WriteFramesLessThan(frame_timestamp_ns))
     return false;
 
-  if (mode_ == kFile) {
-    if (cluster_list_size_ > 0) {
-      // Update old cluster's size
-      Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
+  if (cluster_list_size_ > 0) {
+    // Update old cluster's size
+    Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
 
-      if (!old_cluster || !old_cluster->Finalize())
-        return false;
-    }
-
-    if (output_cues_)
-      new_cuepoint_ = true;
+    if (!old_cluster || !old_cluster->Finalize(true, frame_timestamp_ns))
+      return false;
   }
 
+  if (output_cues_)
+    new_cuepoint_ = true;
+
   if (chunking_ && cluster_list_size_ > 0) {
     chunk_writer_cluster_->Close();
     chunk_count_++;
@@ -2990,24 +3481,25 @@ bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
       return false;
   }
 
-  const uint64 timecode_scale = segment_info_.timecode_scale();
-  const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
+  const uint64_t timecode_scale = segment_info_.timecode_scale();
+  const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
 
-  uint64 cluster_timecode = frame_timecode;
+  uint64_t cluster_timecode = frame_timecode;
 
   if (frames_size_ > 0) {
     const Frame* const f = frames_[0];  // earliest queued frame
-    const uint64 ns = f->timestamp();
-    const uint64 tc = ns / timecode_scale;
+    const uint64_t ns = f->timestamp();
+    const uint64_t tc = ns / timecode_scale;
 
     if (tc < cluster_timecode)
       cluster_timecode = tc;
   }
 
   Cluster*& cluster = cluster_list_[cluster_list_size_];
-  const int64 offset = MaxOffset();
-  cluster = new (std::nothrow) Cluster(cluster_timecode,  // NOLINT
-                                       offset, segment_info_.timecode_scale());
+  const int64_t offset = MaxOffset();
+  cluster = new (std::nothrow)
+      Cluster(cluster_timecode, offset, segment_info_.timecode_scale(),
+              accurate_cluster_duration_, fixed_size_cluster_timecode_);
   if (!cluster)
     return false;
 
@@ -3018,8 +3510,8 @@ bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
   return true;
 }
 
-bool Segment::DoNewClusterProcessing(uint64 track_number,
-                                     uint64 frame_timestamp_ns, bool is_key) {
+bool Segment::DoNewClusterProcessing(uint64_t track_number,
+                                     uint64_t frame_timestamp_ns, bool is_key) {
   for (;;) {
     // Based on the characteristics of the current frame and current
     // cluster, decide whether to create a new cluster.
@@ -3055,12 +3547,12 @@ bool Segment::CheckHeaderInfo() {
     if (!WriteSegmentHeader())
       return false;
 
-    if (!seek_head_.AddSeekEntry(kMkvCluster, MaxOffset()))
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvCluster, MaxOffset()))
       return false;
 
     if (output_cues_ && cues_track_ == 0) {
       // Check for a video track
-      for (uint32 i = 0; i < tracks_.track_entries_size(); ++i) {
+      for (uint32_t i = 0; i < tracks_.track_entries_size(); ++i) {
         const Track* const track = tracks_.GetTrackByIndex(i);
         if (!track)
           return false;
@@ -3085,7 +3577,7 @@ bool Segment::CheckHeaderInfo() {
 }
 
 void Segment::UpdateDocTypeVersion() {
-  for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
+  for (uint32_t index = 0; index < tracks_.track_entries_size(); ++index) {
     const Track* track = tracks_.GetTrackByIndex(index);
     if (track == NULL)
       break;
@@ -3127,14 +3619,14 @@ bool Segment::UpdateChunkName(const char* ext, char** name) const {
   return true;
 }
 
-int64 Segment::MaxOffset() {
+int64_t Segment::MaxOffset() {
   if (!writer_header_)
     return -1;
 
-  int64 offset = writer_header_->Position() - payload_pos_;
+  int64_t offset = writer_header_->Position() - payload_pos_;
 
   if (chunking_) {
-    for (int32 i = 0; i < cluster_list_size_; ++i) {
+    for (int32_t i = 0; i < cluster_list_size_; ++i) {
       Cluster* const cluster = cluster_list_[i];
       offset += cluster->Size();
     }
@@ -3147,11 +3639,11 @@ int64 Segment::MaxOffset() {
 }
 
 bool Segment::QueueFrame(Frame* frame) {
-  const int32 new_size = frames_size_ + 1;
+  const int32_t new_size = frames_size_ + 1;
 
   if (new_size > frames_capacity_) {
     // Add more frames.
-    const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
+    const int32_t new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
 
     if (new_capacity < 1)
       return false;
@@ -3160,7 +3652,7 @@ bool Segment::QueueFrame(Frame* frame) {
     if (!frames)
       return false;
 
-    for (int32 i = 0; i < frames_size_; ++i) {
+    for (int32_t i = 0; i < frames_size_; ++i) {
       frames[i] = frames_[i];
     }
 
@@ -3186,7 +3678,7 @@ int Segment::WriteFramesAll() {
   if (!cluster)
     return -1;
 
-  for (int32 i = 0; i < frames_size_; ++i) {
+  for (int32_t i = 0; i < frames_size_; ++i) {
     Frame*& frame = frames_[i];
     // TODO(jzern/vigneshv): using Segment::AddGenericFrame here would limit the
     // places where |doc_type_version_| needs to be updated.
@@ -3215,7 +3707,7 @@ int Segment::WriteFramesAll() {
   return result;
 }
 
-bool Segment::WriteFramesLessThan(uint64 timestamp) {
+bool Segment::WriteFramesLessThan(uint64_t timestamp) {
   // Check |cluster_list_size_| to see if this is the first cluster. If it is
   // the first cluster the audio frames that are less than the first video
   // timesatmp will be written in a later step.
@@ -3227,11 +3719,11 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
     if (!cluster)
       return false;
 
-    int32 shift_left = 0;
+    int32_t shift_left = 0;
 
     // TODO(fgalligan): Change this to use the durations of frames instead of
     // the next frame's start time if the duration is accurate.
-    for (int32 i = 1; i < frames_size_; ++i) {
+    for (int32_t i = 1; i < frames_size_; ++i) {
       const Frame* const frame_curr = frames_[i];
 
       if (frame_curr->timestamp() > timestamp)
@@ -3262,8 +3754,8 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
       if (shift_left >= frames_size_)
         return false;
 
-      const int32 new_frames_size = frames_size_ - shift_left;
-      for (int32 i = 0; i < new_frames_size; ++i) {
+      const int32_t new_frames_size = frames_size_ - shift_left;
+      for (int32_t i = 0; i < new_frames_size; ++i) {
         frames_[i] = frames_[i + shift_left];
       }
 
similarity index 68%
rename from third_party/libwebm/mkvmuxer.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxer.h
index 03a002c93b3b7bf881e6124075483331b4c936fb..55ba07196df20be05cf3c3c01d410f32bd46de97 100644 (file)
@@ -6,24 +6,31 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#ifndef MKVMUXER_HPP
-#define MKVMUXER_HPP
+#ifndef MKVMUXER_MKVMUXER_H_
+#define MKVMUXER_MKVMUXER_H_
 
-#include "mkvmuxertypes.hpp"
+#include <stdint.h>
+
+#include <cstddef>
+#include <list>
+#include <map>
+
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxertypes.h"
 
 // For a description of the WebM elements see
 // http://www.webmproject.org/code/specs/container/.
 
 namespace mkvparser {
 class IMkvReader;
-}  // end namespace
+}  // namespace mkvparser
 
 namespace mkvmuxer {
 
 class MkvWriter;
 class Segment;
 
-const uint64 kMaxTrackNumber = 126;
+const uint64_t kMaxTrackNumber = 126;
 
 ///////////////////////////////////////////////////////////////
 // Interface used by the mkvmuxer to write out the Mkv data.
@@ -59,15 +66,15 @@ class IMkvWriter {
 
 // 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 doc_type_version);
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version);
 
 // Deprecated. Writes out EBML header with doc_type_version as
 // kDefaultDocTypeVersion. Exists for backward compatibility.
 bool WriteEbmlHeader(IMkvWriter* writer);
 
 // Copies in Chunk from source to destination between the given byte positions
-bool ChunkedCopy(mkvparser::IMkvReader* source, IMkvWriter* dst, int64 start,
-                 int64 size);
+bool ChunkedCopy(mkvparser::IMkvReader* source, IMkvWriter* dst, int64_t start,
+                 int64_t size);
 
 ///////////////////////////////////////////////////////////////
 // Class to hold data the will be written to a block.
@@ -81,10 +88,11 @@ class Frame {
   bool CopyFrom(const Frame& frame);
 
   // Copies |frame| data into |frame_|. Returns true on success.
-  bool Init(const uint8* frame, uint64 length);
+  bool Init(const uint8_t* frame, uint64_t length);
 
   // Copies |additional| data into |additional_|. Returns true on success.
-  bool AddAdditionalData(const uint8* additional, uint64 length, uint64 add_id);
+  bool AddAdditionalData(const uint8_t* additional, uint64_t length,
+                         uint64_t add_id);
 
   // Returns true if the frame has valid parameters.
   bool IsValid() const;
@@ -93,62 +101,70 @@ class Frame {
   // parameters.
   bool CanBeSimpleBlock() const;
 
-  uint64 add_id() const { return add_id_; }
-  const uint8* additional() const { return additional_; }
-  uint64 additional_length() const { return additional_length_; }
-  void set_duration(uint64 duration) { duration_ = duration; }
-  uint64 duration() const { return duration_; }
-  const uint8* frame() const { return frame_; }
+  uint64_t add_id() const { return add_id_; }
+  const uint8_t* additional() const { return additional_; }
+  uint64_t additional_length() const { return additional_length_; }
+  void set_duration(uint64_t duration);
+  uint64_t duration() const { return duration_; }
+  bool duration_set() const { return duration_set_; }
+  const uint8_t* frame() const { return frame_; }
   void set_is_key(bool key) { is_key_ = key; }
   bool is_key() const { return is_key_; }
-  uint64 length() const { return length_; }
-  void set_track_number(uint64 track_number) { track_number_ = track_number; }
-  uint64 track_number() const { return track_number_; }
-  void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
-  uint64 timestamp() const { return timestamp_; }
-  void set_discard_padding(int64 discard_padding) {
+  uint64_t length() const { return length_; }
+  void set_track_number(uint64_t track_number) { track_number_ = track_number; }
+  uint64_t track_number() const { return track_number_; }
+  void set_timestamp(uint64_t timestamp) { timestamp_ = timestamp; }
+  uint64_t timestamp() const { return timestamp_; }
+  void set_discard_padding(int64_t discard_padding) {
     discard_padding_ = discard_padding;
   }
-  int64 discard_padding() const { return discard_padding_; }
-  void set_reference_block_timestamp(int64 reference_block_timestamp);
-  int64 reference_block_timestamp() const { return reference_block_timestamp_; }
+  int64_t discard_padding() const { return discard_padding_; }
+  void set_reference_block_timestamp(int64_t reference_block_timestamp);
+  int64_t reference_block_timestamp() const {
+    return reference_block_timestamp_;
+  }
   bool reference_block_timestamp_set() const {
     return reference_block_timestamp_set_;
   }
 
  private:
   // Id of the Additional data.
-  uint64 add_id_;
+  uint64_t add_id_;
 
   // Pointer to additional data. Owned by this class.
-  uint8* additional_;
+  uint8_t* additional_;
 
   // Length of the additional data.
-  uint64 additional_length_;
+  uint64_t additional_length_;
 
   // Duration of the frame in nanoseconds.
-  uint64 duration_;
+  uint64_t duration_;
+
+  // Flag indicating that |duration_| has been set. Setting duration causes the
+  // frame to be written out as a Block with BlockDuration instead of as a
+  // SimpleBlock.
+  bool duration_set_;
 
   // Pointer to the data. Owned by this class.
-  uint8* frame_;
+  uint8_t* frame_;
 
   // Flag telling if the data should set the key flag of a block.
   bool is_key_;
 
   // Length of the data.
-  uint64 length_;
+  uint64_t length_;
 
   // Mkv track number the data is associated with.
-  uint64 track_number_;
+  uint64_t track_number_;
 
   // Timestamp of the data in nanoseconds.
-  uint64 timestamp_;
+  uint64_t timestamp_;
 
   // Discard padding for the frame.
-  int64 discard_padding_;
+  int64_t discard_padding_;
 
   // Reference block timestamp.
-  int64 reference_block_timestamp_;
+  int64_t reference_block_timestamp_;
 
   // Flag indicating if |reference_block_timestamp_| has been set.
   bool reference_block_timestamp_set_;
@@ -164,19 +180,19 @@ class CuePoint {
   ~CuePoint();
 
   // Returns the size in bytes for the entire CuePoint element.
-  uint64 Size() const;
+  uint64_t Size() const;
 
   // Output the CuePoint element to the writer. Returns true on success.
   bool Write(IMkvWriter* writer) const;
 
-  void set_time(uint64 time) { time_ = time; }
-  uint64 time() const { return time_; }
-  void set_track(uint64 track) { track_ = track; }
-  uint64 track() const { return track_; }
-  void set_cluster_pos(uint64 cluster_pos) { cluster_pos_ = cluster_pos; }
-  uint64 cluster_pos() const { return cluster_pos_; }
-  void set_block_number(uint64 block_number) { block_number_ = block_number; }
-  uint64 block_number() const { return block_number_; }
+  void set_time(uint64_t time) { time_ = time; }
+  uint64_t time() const { return time_; }
+  void set_track(uint64_t track) { track_ = track; }
+  uint64_t track() const { return track_; }
+  void set_cluster_pos(uint64_t cluster_pos) { cluster_pos_ = cluster_pos; }
+  uint64_t cluster_pos() const { return cluster_pos_; }
+  void set_block_number(uint64_t block_number) { block_number_ = block_number; }
+  uint64_t block_number() const { return block_number_; }
   void set_output_block_number(bool output_block_number) {
     output_block_number_ = output_block_number;
   }
@@ -184,19 +200,19 @@ class CuePoint {
 
  private:
   // Returns the size in bytes for the payload of the CuePoint element.
-  uint64 PayloadSize() const;
+  uint64_t PayloadSize() const;
 
   // Absolute timecode according to the segment time base.
-  uint64 time_;
+  uint64_t time_;
 
   // The Track element associated with the CuePoint.
-  uint64 track_;
+  uint64_t track_;
 
   // The position of the Cluster containing the Block.
-  uint64 cluster_pos_;
+  uint64_t cluster_pos_;
 
   // Number of the Block within the Cluster, starting from 1.
-  uint64 block_number_;
+  uint64_t block_number_;
 
   // If true the muxer will write out the block number for the cue if the
   // block number is different than the default of 1. Default is set to true.
@@ -217,15 +233,15 @@ class Cues {
 
   // Returns the cue point by index. Returns NULL if there is no cue point
   // match.
-  CuePoint* GetCueByIndex(int32 index) const;
+  CuePoint* GetCueByIndex(int32_t index) const;
 
   // Returns the total size of the Cues element
-  uint64 Size();
+  uint64_t Size();
 
   // Output the Cues element to the writer. Returns true on success.
   bool Write(IMkvWriter* writer) const;
 
-  int32 cue_entries_size() const { return cue_entries_size_; }
+  int32_t cue_entries_size() const { return cue_entries_size_; }
   void set_output_block_number(bool output_block_number) {
     output_block_number_ = output_block_number;
   }
@@ -233,10 +249,10 @@ class Cues {
 
  private:
   // Number of allocated elements in |cue_entries_|.
-  int32 cue_entries_capacity_;
+  int32_t cue_entries_capacity_;
 
   // Number of CuePoints in |cue_entries_|.
-  int32 cue_entries_size_;
+  int32_t cue_entries_size_;
 
   // CuePoint list.
   CuePoint** cue_entries_;
@@ -258,21 +274,21 @@ class ContentEncAESSettings {
   ~ContentEncAESSettings() {}
 
   // Returns the size in bytes for the ContentEncAESSettings element.
-  uint64 Size() const;
+  uint64_t Size() const;
 
   // Writes out the ContentEncAESSettings element to |writer|. Returns true on
   // success.
   bool Write(IMkvWriter* writer) const;
 
-  uint64 cipher_mode() const { return cipher_mode_; }
+  uint64_t cipher_mode() const { return cipher_mode_; }
 
  private:
   // Returns the size in bytes for the payload of the ContentEncAESSettings
   // element.
-  uint64 PayloadSize() const;
+  uint64_t PayloadSize() const;
 
   // Sub elements
-  uint64 cipher_mode_;
+  uint64_t cipher_mode_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
 };
@@ -291,44 +307,157 @@ class ContentEncoding {
 
   // Sets the content encryption id. Copies |length| bytes from |id| to
   // |enc_key_id_|. Returns true on success.
-  bool SetEncryptionID(const uint8* id, uint64 length);
+  bool SetEncryptionID(const uint8_t* id, uint64_t length);
 
   // Returns the size in bytes for the ContentEncoding element.
-  uint64 Size() const;
+  uint64_t Size() const;
 
   // Writes out the ContentEncoding element to |writer|. Returns true on
   // success.
   bool Write(IMkvWriter* writer) const;
 
-  uint64 enc_algo() const { return enc_algo_; }
-  uint64 encoding_order() const { return encoding_order_; }
-  uint64 encoding_scope() const { return encoding_scope_; }
-  uint64 encoding_type() const { return encoding_type_; }
+  uint64_t enc_algo() const { return enc_algo_; }
+  uint64_t encoding_order() const { return encoding_order_; }
+  uint64_t encoding_scope() const { return encoding_scope_; }
+  uint64_t encoding_type() const { return encoding_type_; }
   ContentEncAESSettings* enc_aes_settings() { return &enc_aes_settings_; }
 
  private:
   // Returns the size in bytes for the encoding elements.
-  uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const;
+  uint64_t EncodingSize(uint64_t compresion_size,
+                        uint64_t encryption_size) const;
 
   // Returns the size in bytes for the encryption elements.
-  uint64 EncryptionSize() const;
+  uint64_t EncryptionSize() const;
 
   // Track element names
-  uint64 enc_algo_;
-  uint8* enc_key_id_;
-  uint64 encoding_order_;
-  uint64 encoding_scope_;
-  uint64 encoding_type_;
+  uint64_t enc_algo_;
+  uint8_t* enc_key_id_;
+  uint64_t encoding_order_;
+  uint64_t encoding_scope_;
+  uint64_t encoding_type_;
 
   // ContentEncAESSettings element.
   ContentEncAESSettings enc_aes_settings_;
 
   // Size of the ContentEncKeyID data in bytes.
-  uint64 enc_key_id_length_;
+  uint64_t enc_key_id_length_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
 };
 
+///////////////////////////////////////////////////////////////
+// Colour element.
+struct PrimaryChromaticity {
+  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;
+  bool Write(IMkvWriter* writer, libwebm::MkvId x_id,
+             libwebm::MkvId y_id) const;
+
+  float x;
+  float y;
+};
+
+class MasteringMetadata {
+ public:
+  static const float kValueNotPresent;
+
+  MasteringMetadata()
+      : luminance_max(kValueNotPresent),
+        luminance_min(kValueNotPresent),
+        r_(NULL),
+        g_(NULL),
+        b_(NULL),
+        white_point_(NULL) {}
+  ~MasteringMetadata() {
+    delete r_;
+    delete g_;
+    delete b_;
+    delete white_point_;
+  }
+
+  // Returns total size of the MasteringMetadata element.
+  uint64_t MasteringMetadataSize() const;
+  bool Write(IMkvWriter* writer) const;
+
+  // Copies non-null chromaticity.
+  bool SetChromaticity(const PrimaryChromaticity* r,
+                       const PrimaryChromaticity* g,
+                       const PrimaryChromaticity* b,
+                       const PrimaryChromaticity* white_point);
+  const PrimaryChromaticity* r() const { return r_; }
+  const PrimaryChromaticity* g() const { return g_; }
+  const PrimaryChromaticity* b() const { return b_; }
+  const PrimaryChromaticity* white_point() const { return white_point_; }
+
+  float luminance_max;
+  float luminance_min;
+
+ private:
+  // Returns size of MasteringMetadata child elements.
+  uint64_t PayloadSize() const;
+
+  PrimaryChromaticity* r_;
+  PrimaryChromaticity* g_;
+  PrimaryChromaticity* b_;
+  PrimaryChromaticity* white_point_;
+};
+
+class Colour {
+ public:
+  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),
+        mastering_metadata_(NULL) {}
+  ~Colour() { delete mastering_metadata_; }
+
+  // Returns total size of the Colour element.
+  uint64_t ColourSize() const;
+  bool Write(IMkvWriter* writer) const;
+
+  // Deep copies |mastering_metadata|.
+  bool SetMasteringMetadata(const MasteringMetadata& mastering_metadata);
+
+  const MasteringMetadata* mastering_metadata() const {
+    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;
+
+ private:
+  // Returns size of Colour child elements.
+  uint64_t PayloadSize() const;
+
+  MasteringMetadata* mastering_metadata_;
+};
+
 ///////////////////////////////////////////////////////////////
 // Track element.
 class Track {
@@ -342,76 +471,76 @@ class Track {
 
   // Returns the ContentEncoding by index. Returns NULL if there is no
   // ContentEncoding match.
-  ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
+  ContentEncoding* GetContentEncodingByIndex(uint32_t index) const;
 
   // Returns the size in bytes for the payload of the Track element.
-  virtual uint64 PayloadSize() const;
+  virtual uint64_t PayloadSize() const;
 
   // Returns the size in bytes of the Track element.
-  virtual uint64 Size() const;
+  virtual uint64_t Size() const;
 
   // Output the Track element to the writer. Returns true on success.
   virtual bool Write(IMkvWriter* writer) const;
 
   // Sets the CodecPrivate element of the Track element. Copies |length|
   // bytes from |codec_private| to |codec_private_|. Returns true on success.
-  bool SetCodecPrivate(const uint8* codec_private, uint64 length);
+  bool SetCodecPrivate(const uint8_t* codec_private, uint64_t length);
 
   void set_codec_id(const char* codec_id);
   const char* codec_id() const { return codec_id_; }
-  const uint8* codec_private() const { return codec_private_; }
+  const uint8_t* codec_private() const { return codec_private_; }
   void set_language(const char* language);
   const char* language() const { return language_; }
-  void set_max_block_additional_id(uint64 max_block_additional_id) {
+  void set_max_block_additional_id(uint64_t max_block_additional_id) {
     max_block_additional_id_ = max_block_additional_id;
   }
-  uint64 max_block_additional_id() const { return max_block_additional_id_; }
+  uint64_t max_block_additional_id() const { return max_block_additional_id_; }
   void set_name(const char* name);
   const char* name() const { return name_; }
-  void set_number(uint64 number) { number_ = number; }
-  uint64 number() const { return number_; }
-  void set_type(uint64 type) { type_ = type; }
-  uint64 type() const { return type_; }
-  void set_uid(uint64 uid) { uid_ = uid; }
-  uint64 uid() const { return uid_; }
-  void set_codec_delay(uint64 codec_delay) { codec_delay_ = codec_delay; }
-  uint64 codec_delay() const { return codec_delay_; }
-  void set_seek_pre_roll(uint64 seek_pre_roll) {
+  void set_number(uint64_t number) { number_ = number; }
+  uint64_t number() const { return number_; }
+  void set_type(uint64_t type) { type_ = type; }
+  uint64_t type() const { return type_; }
+  void set_uid(uint64_t uid) { uid_ = uid; }
+  uint64_t uid() const { return uid_; }
+  void set_codec_delay(uint64_t codec_delay) { codec_delay_ = codec_delay; }
+  uint64_t codec_delay() const { return codec_delay_; }
+  void set_seek_pre_roll(uint64_t seek_pre_roll) {
     seek_pre_roll_ = seek_pre_roll;
   }
-  uint64 seek_pre_roll() const { return seek_pre_roll_; }
-  void set_default_duration(uint64 default_duration) {
+  uint64_t seek_pre_roll() const { return seek_pre_roll_; }
+  void set_default_duration(uint64_t default_duration) {
     default_duration_ = default_duration;
   }
-  uint64 default_duration() const { return default_duration_; }
+  uint64_t default_duration() const { return default_duration_; }
 
-  uint64 codec_private_length() const { return codec_private_length_; }
-  uint32 content_encoding_entries_size() const {
+  uint64_t codec_private_length() const { return codec_private_length_; }
+  uint32_t content_encoding_entries_size() const {
     return content_encoding_entries_size_;
   }
 
  private:
   // Track element names.
   char* codec_id_;
-  uint8* codec_private_;
+  uint8_t* codec_private_;
   char* language_;
-  uint64 max_block_additional_id_;
+  uint64_t max_block_additional_id_;
   char* name_;
-  uint64 number_;
-  uint64 type_;
-  uint64 uid_;
-  uint64 codec_delay_;
-  uint64 seek_pre_roll_;
-  uint64 default_duration_;
+  uint64_t number_;
+  uint64_t type_;
+  uint64_t uid_;
+  uint64_t codec_delay_;
+  uint64_t seek_pre_roll_;
+  uint64_t default_duration_;
 
   // Size of the CodecPrivate data in bytes.
-  uint64 codec_private_length_;
+  uint64_t codec_private_length_;
 
   // ContentEncoding element list.
   ContentEncoding** content_encoding_entries_;
 
   // Number of ContentEncoding elements added.
-  uint32 content_encoding_entries_size_;
+  uint32_t content_encoding_entries_size_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
 };
@@ -437,56 +566,63 @@ class VideoTrack : public Track {
 
   // Returns the size in bytes for the payload of the Track element plus the
   // video specific elements.
-  virtual uint64 PayloadSize() const;
+  virtual uint64_t PayloadSize() const;
 
   // Output the VideoTrack element to the writer. Returns true on success.
   virtual bool Write(IMkvWriter* writer) const;
 
   // Sets the video's stereo mode. Returns true on success.
-  bool SetStereoMode(uint64 stereo_mode);
+  bool SetStereoMode(uint64_t stereo_mode);
 
   // Sets the video's alpha mode. Returns true on success.
-  bool SetAlphaMode(uint64 alpha_mode);
-
-  void set_display_height(uint64 height) { display_height_ = height; }
-  uint64 display_height() const { return display_height_; }
-  void set_display_width(uint64 width) { display_width_ = width; }
-  uint64 display_width() const { return display_width_; }
-
-  void set_crop_left(uint64 crop_left) { crop_left_ = crop_left; }
-  uint64 crop_left() const { return crop_left_; }
-  void set_crop_right(uint64 crop_right) { crop_right_ = crop_right; }
-  uint64 crop_right() const { return crop_right_; }
-  void set_crop_top(uint64 crop_top) { crop_top_ = crop_top; }
-  uint64 crop_top() const { return crop_top_; }
-  void set_crop_bottom(uint64 crop_bottom) { crop_bottom_ = crop_bottom; }
-  uint64 crop_bottom() const { return crop_bottom_; }
+  bool SetAlphaMode(uint64_t alpha_mode);
+
+  void set_display_height(uint64_t height) { display_height_ = height; }
+  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_crop_left(uint64_t crop_left) { crop_left_ = crop_left; }
+  uint64_t crop_left() const { return crop_left_; }
+  void set_crop_right(uint64_t crop_right) { crop_right_ = crop_right; }
+  uint64_t crop_right() const { return crop_right_; }
+  void set_crop_top(uint64_t crop_top) { crop_top_ = crop_top; }
+  uint64_t crop_top() const { return crop_top_; }
+  void set_crop_bottom(uint64_t crop_bottom) { crop_bottom_ = crop_bottom; }
+  uint64_t crop_bottom() const { return crop_bottom_; }
 
   void set_frame_rate(double frame_rate) { frame_rate_ = frame_rate; }
   double frame_rate() const { return frame_rate_; }
-  void set_height(uint64 height) { height_ = height; }
-  uint64 height() const { return height_; }
-  uint64 stereo_mode() { return stereo_mode_; }
-  uint64 alpha_mode() { return alpha_mode_; }
-  void set_width(uint64 width) { width_ = width; }
-  uint64 width() const { return width_; }
+  void set_height(uint64_t height) { height_ = height; }
+  uint64_t height() const { return height_; }
+  uint64_t stereo_mode() { return stereo_mode_; }
+  uint64_t alpha_mode() { return alpha_mode_; }
+  void set_width(uint64_t width) { width_ = width; }
+  uint64_t width() const { return width_; }
+
+  Colour* colour() { return colour_; }
+
+  // Deep copies |colour|.
+  bool SetColour(const Colour& colour);
 
  private:
   // Returns the size in bytes of the Video element.
-  uint64 VideoPayloadSize() const;
+  uint64_t VideoPayloadSize() const;
 
   // Video track element names.
-  uint64 display_height_;
-  uint64 display_width_;
-  uint64 crop_left_;
-  uint64 crop_right_;
-  uint64 crop_top_;
-  uint64 crop_bottom_;
+  uint64_t display_height_;
+  uint64_t display_width_;
+  uint64_t crop_left_;
+  uint64_t crop_right_;
+  uint64_t crop_top_;
+  uint64_t crop_bottom_;
   double frame_rate_;
-  uint64 height_;
-  uint64 stereo_mode_;
-  uint64 alpha_mode_;
-  uint64 width_;
+  uint64_t height_;
+  uint64_t stereo_mode_;
+  uint64_t alpha_mode_;
+  uint64_t width_;
+
+  Colour* colour_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
 };
@@ -501,22 +637,22 @@ class AudioTrack : public Track {
 
   // Returns the size in bytes for the payload of the Track element plus the
   // audio specific elements.
-  virtual uint64 PayloadSize() const;
+  virtual uint64_t PayloadSize() const;
 
   // Output the AudioTrack element to the writer. Returns true on success.
   virtual bool Write(IMkvWriter* writer) const;
 
-  void set_bit_depth(uint64 bit_depth) { bit_depth_ = bit_depth; }
-  uint64 bit_depth() const { return bit_depth_; }
-  void set_channels(uint64 channels) { channels_ = channels; }
-  uint64 channels() const { return channels_; }
+  void set_bit_depth(uint64_t bit_depth) { bit_depth_ = bit_depth; }
+  uint64_t bit_depth() const { return bit_depth_; }
+  void set_channels(uint64_t channels) { channels_ = channels; }
+  uint64_t channels() const { return channels_; }
   void set_sample_rate(double sample_rate) { sample_rate_ = sample_rate; }
   double sample_rate() const { return sample_rate_; }
 
  private:
   // Audio track element names.
-  uint64 bit_depth_;
-  uint64 channels_;
+  uint64_t bit_depth_;
+  uint64_t channels_;
   double sample_rate_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
@@ -542,32 +678,35 @@ class Tracks {
   // deleted by the Tracks object. Returns true on success. |number| is the
   // number to use for the track. |number| must be >= 0. If |number| == 0
   // then the muxer will decide on the track number.
-  bool AddTrack(Track* track, int32 number);
+  bool AddTrack(Track* track, int32_t number);
 
   // Returns the track by index. Returns NULL if there is no track match.
-  const Track* GetTrackByIndex(uint32 idx) const;
+  const Track* GetTrackByIndex(uint32_t idx) const;
 
   // Search the Tracks and return the track that matches |tn|. Returns NULL
   // if there is no track match.
-  Track* GetTrackByNumber(uint64 track_number) const;
+  Track* GetTrackByNumber(uint64_t track_number) const;
 
   // Returns true if the track number is an audio track.
-  bool TrackIsAudio(uint64 track_number) const;
+  bool TrackIsAudio(uint64_t track_number) const;
 
   // Returns true if the track number is a video track.
-  bool TrackIsVideo(uint64 track_number) const;
+  bool TrackIsVideo(uint64_t track_number) const;
 
   // Output the Tracks element to the writer. Returns true on success.
   bool Write(IMkvWriter* writer) const;
 
-  uint32 track_entries_size() const { return track_entries_size_; }
+  uint32_t track_entries_size() const { return track_entries_size_; }
 
  private:
   // Track element list.
   Track** track_entries_;
 
   // Number of Track elements added.
-  uint32 track_entries_size_;
+  uint32_t track_entries_size_;
+
+  // Whether or not Tracks element has already been written via IMkvWriter.
+  mutable bool wrote_tracks_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tracks);
 };
@@ -585,12 +724,12 @@ class Chapter {
 
   // Converts the nanosecond start and stop times of this chapter to
   // their corresponding timecode values, and stores them that way.
-  void set_time(const Segment& segment, uint64 start_time_ns,
-                uint64 end_time_ns);
+  void set_time(const Segment& segment, uint64_t start_time_ns,
+                uint64_t end_time_ns);
 
   // Sets the uid for this chapter. Primarily used to enable
   // deterministic output from the muxer.
-  void set_uid(const uint64 uid) { uid_ = uid; }
+  void set_uid(const uint64_t uid) { uid_ = uid; }
 
   // Add a title string to this chapter, per the semantics described
   // here:
@@ -637,7 +776,7 @@ class Chapter {
     // If |writer| is non-NULL, serialize the Display sub-element of
     // the Atom into the stream.  Returns the Display element size on
     // success, 0 if error.
-    uint64 WriteDisplay(IMkvWriter* writer) const;
+    uint64_t WriteDisplay(IMkvWriter* writer) const;
 
    private:
     char* title_;
@@ -670,20 +809,20 @@ class Chapter {
   // If |writer| is non-NULL, serialize the Atom sub-element into the
   // stream.  Returns the total size of the element on success, 0 if
   // error.
-  uint64 WriteAtom(IMkvWriter* writer) const;
+  uint64_t WriteAtom(IMkvWriter* writer) const;
 
   // The string identifier for this chapter (corresponds to WebVTT cue
   // identifier).
   char* id_;
 
   // Start timecode of the chapter.
-  uint64 start_timecode_;
+  uint64_t start_timecode_;
 
   // Stop timecode of the chapter.
-  uint64 end_timecode_;
+  uint64_t end_timecode_;
 
   // The binary identifier for this chapter.
-  uint64 uid_;
+  uint64_t uid_;
 
   // The Atom element can contain multiple Display sub-elements, as
   // the same logical title can be rendered in different languages.
@@ -723,7 +862,7 @@ class Chapters {
   // If |writer| is non-NULL, serialize the Edition sub-element of the
   // Chapters element into the stream.  Returns the Edition element
   // size on success, 0 if error.
-  uint64 WriteEdition(IMkvWriter* writer) const;
+  uint64_t WriteEdition(IMkvWriter* writer) const;
 
   // Total length of the chapters_ array.
   int chapters_size_;
@@ -768,7 +907,7 @@ class Tag {
     // If |writer| is non-NULL, serialize the SimpleTag sub-element of
     // the Atom into the stream.  Returns the SimpleTag element size on
     // success, 0 if error.
-    uint64 Write(IMkvWriter* writer) const;
+    uint64_t Write(IMkvWriter* writer) const;
 
    private:
     char* tag_name_;
@@ -795,7 +934,7 @@ class Tag {
   // If |writer| is non-NULL, serialize the Tag sub-element into the
   // stream.  Returns the total size of the element on success, 0 if
   // error.
-  uint64 Write(IMkvWriter* writer) const;
+  uint64_t Write(IMkvWriter* writer) const;
 
   // The Atom element can contain multiple SimpleTag sub-elements
   SimpleTag* simple_tags_;
@@ -853,7 +992,9 @@ class Cluster {
   // |timecode| is the absolute timecode of the cluster. |cues_pos| is the
   // position for the cluster within the segment that should be written in
   // the cues element. |timecode_scale| is the timecode scale of the segment.
-  Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale);
+  Cluster(uint64_t timecode, int64_t cues_pos, uint64_t timecode_scale,
+          bool write_last_frame_with_duration = false,
+          bool fixed_size_timecode = false);
   ~Cluster();
 
   bool Init(IMkvWriter* ptr_writer);
@@ -872,8 +1013,8 @@ class Cluster {
   //   timecode:     Absolute (not relative to cluster) timestamp of the
   //                 frame, expressed in timecode units.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                uint64 timecode,  // timecode units (absolute)
+  bool AddFrame(const uint8_t* data, uint64_t length, uint64_t track_number,
+                uint64_t timecode,  // timecode units (absolute)
                 bool is_key);
 
   // Adds a frame to be output in the file. The frame is written out through
@@ -889,10 +1030,11 @@ class Cluster {
   //   abs_timecode: Absolute (not relative to cluster) timestamp of the
   //                 frame, expressed in timecode units.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrameWithAdditional(const uint8* data, uint64 length,
-                              const uint8* additional, uint64 additional_length,
-                              uint64 add_id, uint64 track_number,
-                              uint64 abs_timecode, bool is_key);
+  bool AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+                              const uint8_t* additional,
+                              uint64_t additional_length, uint64_t add_id,
+                              uint64_t track_number, uint64_t abs_timecode,
+                              bool is_key);
 
   // Adds a frame to be output in the file. The frame is written out through
   // |writer_| if successful. Returns true on success.
@@ -905,9 +1047,10 @@ class Cluster {
   //   abs_timecode: Absolute (not relative to cluster) timestamp of the
   //                 frame, expressed in timecode units.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                  int64 discard_padding, uint64 track_number,
-                                  uint64 abs_timecode, bool is_key);
+  bool AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+                                  int64_t discard_padding,
+                                  uint64_t track_number, uint64_t abs_timecode,
+                                  bool is_key);
 
   // Writes a frame of metadata to the output medium; returns true on
   // success.
@@ -923,31 +1066,53 @@ class Cluster {
   // The metadata frame is written as a block group, with a duration
   // sub-element but no reference time sub-elements (indicating that
   // it is considered a keyframe, per Matroska semantics).
-  bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                   uint64 timecode, uint64 duration);
+  bool AddMetadata(const uint8_t* data, uint64_t length, uint64_t track_number,
+                   uint64_t timecode, uint64_t duration);
 
   // Increments the size of the cluster's data in bytes.
-  void AddPayloadSize(uint64 size);
+  void AddPayloadSize(uint64_t size);
 
   // Closes the cluster so no more data can be written to it. Will update the
-  // cluster's size if |writer_| is seekable. Returns true on success.
+  // cluster's size if |writer_| is seekable. Returns true on success. This
+  // variant of Finalize() fails when |write_last_frame_with_duration_| is set
+  // to true.
   bool Finalize();
 
+  // Closes the cluster so no more data can be written to it. Will update the
+  // cluster's size if |writer_| is seekable. Returns true on success.
+  // Inputs:
+  //   set_last_frame_duration: Boolean indicating whether or not the duration
+  //                            of the last frame should be set. If set to
+  //                            false, the |duration| value is ignored and
+  //                            |write_last_frame_with_duration_| will not be
+  //                            honored.
+  //   duration: Duration of the Cluster in timecode scale.
+  bool Finalize(bool set_last_frame_duration, uint64_t duration);
+
   // Returns the size in bytes for the entire Cluster element.
-  uint64 Size() const;
+  uint64_t Size() const;
 
   // Given |abs_timecode|, calculates timecode relative to most recent timecode.
   // Returns -1 on failure, or a relative timecode.
-  int64 GetRelativeTimecode(int64 abs_timecode) const;
-
-  int64 size_position() const { return size_position_; }
-  int32 blocks_added() const { return blocks_added_; }
-  uint64 payload_size() const { return payload_size_; }
-  int64 position_for_cues() const { return position_for_cues_; }
-  uint64 timecode() const { return timecode_; }
-  uint64 timecode_scale() const { return timecode_scale_; }
+  int64_t GetRelativeTimecode(int64_t abs_timecode) const;
+
+  int64_t size_position() const { return size_position_; }
+  int32_t blocks_added() const { return blocks_added_; }
+  uint64_t payload_size() const { return payload_size_; }
+  int64_t position_for_cues() const { return position_for_cues_; }
+  uint64_t timecode() const { return timecode_; }
+  uint64_t timecode_scale() const { return timecode_scale_; }
+  void set_write_last_frame_with_duration(bool write_last_frame_with_duration) {
+    write_last_frame_with_duration_ = write_last_frame_with_duration;
+  }
+  bool write_last_frame_with_duration() const {
+    return write_last_frame_with_duration_;
+  }
 
  private:
+  // Iterator type for the |stored_frames_| map.
+  typedef std::map<uint64_t, std::list<Frame*> >::iterator FrameMapIterator;
+
   // Utility method that confirms that blocks can still be added, and that the
   // cluster header has been written. Used by |DoWriteFrame*|. Returns true
   // when successful.
@@ -955,37 +1120,58 @@ class Cluster {
 
   // Utility method used by the |DoWriteFrame*| methods that handles the book
   // keeping required after each block is written.
-  void PostWriteBlock(uint64 element_size);
+  void PostWriteBlock(uint64_t element_size);
 
   // Does some verification and calls WriteFrame.
   bool DoWriteFrame(const Frame* const frame);
 
+  // Either holds back the given frame, or writes it out depending on whether or
+  // not |write_last_frame_with_duration_| is set.
+  bool QueueOrWriteFrame(const Frame* const frame);
+
   // Outputs the Cluster header to |writer_|. Returns true on success.
   bool WriteClusterHeader();
 
   // Number of blocks added to the cluster.
-  int32 blocks_added_;
+  int32_t blocks_added_;
 
   // Flag telling if the cluster has been closed.
   bool finalized_;
 
+  // Flag indicating whether the cluster's timecode will always be written out
+  // using 8 bytes.
+  bool fixed_size_timecode_;
+
   // Flag telling if the cluster's header has been written.
   bool header_written_;
 
   // The size of the cluster elements in bytes.
-  uint64 payload_size_;
+  uint64_t payload_size_;
 
   // The file position used for cue points.
-  const int64 position_for_cues_;
+  const int64_t position_for_cues_;
 
   // The file position of the cluster's size element.
-  int64 size_position_;
+  int64_t size_position_;
 
   // The absolute timecode of the cluster.
-  const uint64 timecode_;
+  const uint64_t timecode_;
 
   // The timecode scale of the Segment containing the cluster.
-  const uint64 timecode_scale_;
+  const uint64_t timecode_scale_;
+
+  // Flag indicating whether the last frame of the cluster should be written as
+  // a Block with Duration. If set to true, then it will result in holding back
+  // of frames and the parameterized version of Finalize() must be called to
+  // finish writing the Cluster.
+  bool write_last_frame_with_duration_;
+
+  // Map used to hold back frames, if required. Track number is the key.
+  std::map<uint64_t, std::list<Frame*> > stored_frames_;
+
+  // Map from track number to the timestamp of the last block written for that
+  // track.
+  std::map<uint64_t, uint64_t> last_block_timestamp_;
 
   // Pointer to the writer object. Not owned by this class.
   IMkvWriter* writer_;
@@ -1006,42 +1192,42 @@ class SeekHead {
   // Adds a seek entry to be written out when the element is finalized. |id|
   // must be the coded mkv element id. |pos| is the file position of the
   // element. Returns true on success.
-  bool AddSeekEntry(uint32 id, uint64 pos);
+  bool AddSeekEntry(uint32_t id, uint64_t pos);
 
   // Writes out SeekHead and SeekEntry elements. Returns true on success.
   bool Finalize(IMkvWriter* writer) const;
 
   // Returns the id of the Seek Entry at the given index. Returns -1 if index is
   // out of range.
-  uint32 GetId(int index) const;
+  uint32_t GetId(int index) const;
 
   // Returns the position of the Seek Entry at the given index. Returns -1 if
   // index is out of range.
-  uint64 GetPosition(int index) const;
+  uint64_t GetPosition(int index) const;
 
   // Sets the Seek Entry id and position at given index.
   // Returns true on success.
-  bool SetSeekEntry(int index, uint32 id, uint64 position);
+  bool SetSeekEntry(int index, uint32_t id, uint64_t position);
 
   // Reserves space by writing out a Void element which will be updated with
   // a SeekHead element later. Returns true on success.
   bool Write(IMkvWriter* writer);
 
   // We are going to put a cap on the number of Seek Entries.
-  const static int32 kSeekEntryCount = 5;
+  const static int32_t kSeekEntryCount = 5;
 
  private:
   // Returns the maximum size in bytes of one seek entry.
-  uint64 MaxEntrySize() const;
+  uint64_t MaxEntrySize() const;
 
   // Seek entry id element list.
-  uint32 seek_entry_id_[kSeekEntryCount];
+  uint32_t seek_entry_id_[kSeekEntryCount];
 
   // Seek entry pos element list.
-  uint64 seek_entry_pos_[kSeekEntryCount];
+  uint64_t seek_entry_pos_[kSeekEntryCount];
 
   // The file position of SeekHead element.
-  int64 start_pos_;
+  int64_t start_pos_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
 };
@@ -1067,12 +1253,12 @@ class SegmentInfo {
   double duration() const { return duration_; }
   void set_muxing_app(const char* app);
   const char* muxing_app() const { return muxing_app_; }
-  void set_timecode_scale(uint64 scale) { timecode_scale_ = scale; }
-  uint64 timecode_scale() const { return timecode_scale_; }
+  void set_timecode_scale(uint64_t scale) { timecode_scale_ = scale; }
+  uint64_t timecode_scale() const { return timecode_scale_; }
   void set_writing_app(const char* app);
   const char* writing_app() const { return writing_app_; }
-  void set_date_utc(int64 date_utc) { date_utc_ = date_utc; }
-  int64 date_utc() const { return date_utc_; }
+  void set_date_utc(int64_t date_utc) { date_utc_ = date_utc; }
+  int64_t date_utc() const { return date_utc_; }
 
  private:
   // Segment Information element names.
@@ -1081,14 +1267,14 @@ class SegmentInfo {
   double duration_;
   // Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
   char* muxing_app_;
-  uint64 timecode_scale_;
+  uint64_t timecode_scale_;
   // Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
   char* writing_app_;
   // LLONG_MIN when DateUTC is not set.
-  int64 date_utc_;
+  int64_t date_utc_;
 
   // The file position of the duration element.
-  int64 duration_pos_;
+  int64_t duration_pos_;
 
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
 };
@@ -1108,8 +1294,8 @@ class Segment {
     kBeforeClusters = 0x1  // Position Cues before Clusters
   };
 
-  const static uint32 kDefaultDocTypeVersion = 2;
-  const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
+  const static uint32_t kDefaultDocTypeVersion = 2;
+  const static uint64_t kDefaultMaxClusterDuration = 30000000000ULL;
 
   Segment();
   ~Segment();
@@ -1123,13 +1309,13 @@ class Segment {
   // error. |number| is the number to use for the track.  |number|
   // must be >= 0. If |number| == 0 then the muxer will decide on the
   // track number.
-  Track* AddTrack(int32 number);
+  Track* AddTrack(int32_t number);
 
   // Adds a Vorbis audio track to the segment. Returns the number of the track
   // on success, 0 on error. |number| is the number to use for the audio track.
   // |number| must be >= 0. If |number| == 0 then the muxer will decide on
   // the track number.
-  uint64 AddAudioTrack(int32 sample_rate, int32 channels, int32 number);
+  uint64_t AddAudioTrack(int32_t sample_rate, int32_t channels, int32_t number);
 
   // Adds an empty chapter to the chapters of this segment.  Returns
   // non-NULL on success.  After adding the chapter, the caller should
@@ -1145,7 +1331,7 @@ class Segment {
   // nanoseconds of the cue's time. |track| is the Track of the Cue. This
   // function must be called after AddFrame to calculate the correct
   // BlockNumber for the CuePoint. Returns true on success.
-  bool AddCuePoint(uint64 timestamp, uint64 track);
+  bool AddCuePoint(uint64_t timestamp, uint64_t track);
 
   // Adds a frame to be output in the file. Returns true on success.
   // Inputs:
@@ -1155,8 +1341,8 @@ class Segment {
   //                 functions.
   //   timestamp:    Timestamp of the frame in nanoseconds from 0.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                uint64 timestamp_ns, bool is_key);
+  bool AddFrame(const uint8_t* data, uint64_t length, uint64_t track_number,
+                uint64_t timestamp_ns, bool is_key);
 
   // Writes a frame of metadata to the output medium; returns true on
   // success.
@@ -1172,8 +1358,8 @@ class Segment {
   // The metadata frame is written as a block group, with a duration
   // sub-element but no reference time sub-elements (indicating that
   // it is considered a keyframe, per Matroska semantics).
-  bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                   uint64 timestamp_ns, uint64 duration_ns);
+  bool AddMetadata(const uint8_t* data, uint64_t length, uint64_t track_number,
+                   uint64_t timestamp_ns, uint64_t duration_ns);
 
   // Writes a frame with additional data to the output medium; returns true on
   // success.
@@ -1188,10 +1374,11 @@ class Segment {
   //   timestamp:    Absolute timestamp of the frame, expressed in nanosecond
   //                 units.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrameWithAdditional(const uint8* data, uint64 length,
-                              const uint8* additional, uint64 additional_length,
-                              uint64 add_id, uint64 track_number,
-                              uint64 timestamp, bool is_key);
+  bool AddFrameWithAdditional(const uint8_t* data, uint64_t length,
+                              const uint8_t* additional,
+                              uint64_t additional_length, uint64_t add_id,
+                              uint64_t track_number, uint64_t timestamp,
+                              bool is_key);
 
   // Writes a frame with DiscardPadding to the output medium; returns true on
   // success.
@@ -1204,9 +1391,10 @@ class Segment {
   //   timestamp:    Absolute timestamp of the frame, expressed in nanosecond
   //                 units.
   //   is_key:       Flag telling whether or not this frame is a key frame.
-  bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                  int64 discard_padding, uint64 track_number,
-                                  uint64 timestamp, bool is_key);
+  bool AddFrameWithDiscardPadding(const uint8_t* data, uint64_t length,
+                                  int64_t discard_padding,
+                                  uint64_t track_number, uint64_t timestamp,
+                                  bool is_key);
 
   // Writes a Frame to the output medium. Chooses the correct way of writing
   // the frame (Block vs SimpleBlock) based on the parameters passed.
@@ -1218,7 +1406,7 @@ class Segment {
   // success, 0 on error. |number| is the number to use for the video track.
   // |number| must be >= 0. If |number| == 0 then the muxer will decide on
   // the track number.
-  uint64 AddVideoTrack(int32 width, int32 height, int32 number);
+  uint64_t AddVideoTrack(int32_t width, int32_t height, int32_t number);
 
   // This function must be called after Finalize() if you need a copy of the
   // output with Cues written before the Clusters. It will return false if the
@@ -1237,7 +1425,7 @@ class Segment {
   // Sets which track to use for the Cues element. Must have added the track
   // before calling this function. Returns true on success. |track_number| is
   // returned by the Add track functions.
-  bool CuesTrack(uint64 track_number);
+  bool CuesTrack(uint64_t track_number);
 
   // This will force the muxer to create a new Cluster when the next frame is
   // added.
@@ -1257,11 +1445,17 @@ class Segment {
 
   // Search the Tracks and return the track that matches |track_number|.
   // Returns NULL if there is no track match.
-  Track* GetTrackByNumber(uint64 track_number) const;
+  Track* GetTrackByNumber(uint64_t track_number) const;
 
   // Toggles whether to output a cues element.
   void OutputCues(bool output_cues);
 
+  // Toggles whether to write the last frame in each Cluster with Duration.
+  void AccurateClusterDuration(bool accurate_cluster_duration);
+
+  // Toggles whether to write the Cluster Timecode using exactly 8 bytes.
+  void UseFixedSizeClusterTimecode(bool fixed_size_cluster_timecode);
+
   // Sets if the muxer will output files in chunks or not. |chunking| is a
   // flag telling whether or not to turn on chunking. |filename| is the base
   // filename for the chunk files. The header chunk file will be named
@@ -1274,15 +1468,15 @@ class Segment {
   bool SetChunking(bool chunking, const char* filename);
 
   bool chunking() const { return chunking_; }
-  uint64 cues_track() const { return cues_track_; }
-  void set_max_cluster_duration(uint64 max_cluster_duration) {
+  uint64_t cues_track() const { return cues_track_; }
+  void set_max_cluster_duration(uint64_t max_cluster_duration) {
     max_cluster_duration_ = max_cluster_duration;
   }
-  uint64 max_cluster_duration() const { return max_cluster_duration_; }
-  void set_max_cluster_size(uint64 max_cluster_size) {
+  uint64_t max_cluster_duration() const { return max_cluster_duration_; }
+  void set_max_cluster_size(uint64_t max_cluster_size) {
     max_cluster_size_ = max_cluster_size;
   }
-  uint64 max_cluster_size() const { return max_cluster_size_; }
+  uint64_t max_cluster_size() const { return max_cluster_size_; }
   void set_mode(Mode mode) { mode_ = mode; }
   Mode mode() const { return mode_; }
   CuesPosition cues_position() const { return cues_position_; }
@@ -1306,7 +1500,7 @@ class Segment {
   // Returns the maximum offset within the segment's payload. When chunking
   // this function is needed to determine offsets of elements within the
   // chunked files. Returns -1 on error.
-  int64 MaxOffset();
+  int64_t MaxOffset();
 
   // Adds the frame to our frame array.
   bool QueueFrame(Frame* frame);
@@ -1318,7 +1512,7 @@ class Segment {
   // Output all frames that are queued that have an end time that is less
   // then |timestamp|. Returns true on success and if there are no frames
   // queued.
-  bool WriteFramesLessThan(uint64 timestamp);
+  bool WriteFramesLessThan(uint64_t timestamp);
 
   // Outputs the segment header, Segment Information element, SeekHead element,
   // and Tracks element to |writer_|.
@@ -1332,16 +1526,17 @@ class Segment {
   //  0 = do not create a new cluster, and write frame to the existing cluster
   //  1 = create a new cluster, and write frame to that new cluster
   //  2 = create a new cluster, and re-run test
-  int TestFrame(uint64 track_num, uint64 timestamp_ns, bool key) const;
+  int TestFrame(uint64_t track_num, uint64_t timestamp_ns, bool key) const;
 
   // Create a new cluster, using the earlier of the first enqueued
   // frame, or the indicated time. Returns true on success.
-  bool MakeNewCluster(uint64 timestamp_ns);
+  bool MakeNewCluster(uint64_t timestamp_ns);
 
   // Checks whether a new cluster needs to be created, and if so
   // creates a new cluster. Returns false if creation of a new cluster
   // was necessary but creation was not successful.
-  bool DoNewClusterProcessing(uint64 track_num, uint64 timestamp_ns, bool key);
+  bool DoNewClusterProcessing(uint64_t track_num, uint64_t timestamp_ns,
+                              bool key);
 
   // Adjusts Cue Point values (to place Cues before Clusters) so that they
   // reflect the correct offsets.
@@ -1355,7 +1550,8 @@ class Segment {
   //        accounted for.
   // index - index in the list of Cues which is currently being adjusted.
   // cue_size - sum of size of all the CuePoint elements.
-  void MoveCuesBeforeClustersHelper(uint64 diff, int index, uint64* cue_size);
+  void MoveCuesBeforeClustersHelper(uint64_t diff, int index,
+                                    uint64_t* cue_size);
 
   // Seeds the random number generator used to make UIDs.
   unsigned int seed_;
@@ -1394,22 +1590,22 @@ class Segment {
   char* chunking_base_name_;
 
   // File position offset where the Clusters end.
-  int64 cluster_end_offset_;
+  int64_t cluster_end_offset_;
 
   // List of clusters.
   Cluster** cluster_list_;
 
   // Number of cluster pointers allocated in the cluster list.
-  int32 cluster_list_capacity_;
+  int32_t cluster_list_capacity_;
 
   // Number of clusters in the cluster list.
-  int32 cluster_list_size_;
+  int32_t cluster_list_size_;
 
   // Indicates whether Cues should be written before or after Clusters
   CuesPosition cues_position_;
 
   // Track number that is associated with the cues element for this segment.
-  uint64 cues_track_;
+  uint64_t cues_track_;
 
   // Tells the muxer to force a new cluster on the next Block.
   bool force_new_cluster_;
@@ -1421,10 +1617,10 @@ class Segment {
   Frame** frames_;
 
   // Number of frame pointers allocated in the frame list.
-  int32 frames_capacity_;
+  int32_t frames_capacity_;
 
   // Number of frames in the frame list.
-  int32 frames_size_;
+  int32_t frames_size_;
 
   // Flag telling if a video track has been added to the segment.
   bool has_video_;
@@ -1433,23 +1629,23 @@ class Segment {
   bool header_written_;
 
   // Duration of the last block in nanoseconds.
-  uint64 last_block_duration_;
+  uint64_t last_block_duration_;
 
   // Last timestamp in nanoseconds added to a cluster.
-  uint64 last_timestamp_;
+  uint64_t last_timestamp_;
 
   // Last timestamp in nanoseconds by track number added to a cluster.
-  uint64 last_track_timestamp_[kMaxTrackNumber];
+  uint64_t last_track_timestamp_[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.
-  uint64 max_cluster_duration_;
+  uint64_t max_cluster_duration_;
 
   // Maximum size in bytes for a cluster. This variable is a guideline and
   // some clusters may have a larger size. Default is 0 which signifies that
   // the muxer will decide the size.
-  uint64 max_cluster_size_;
+  uint64_t max_cluster_size_;
 
   // The mode that segment is in. If set to |kLive| the writer must not
   // seek backwards.
@@ -1462,22 +1658,29 @@ class Segment {
   // Flag whether or not the muxer should output a Cues element.
   bool output_cues_;
 
+  // Flag whether or not the last frame in each Cluster will have a Duration
+  // element in it.
+  bool accurate_cluster_duration_;
+
+  // Flag whether or not to write the Cluster Timecode using exactly 8 bytes.
+  bool fixed_size_cluster_timecode_;
+
   // The size of the EBML header, used to validate the header if
   // WriteEbmlHeader() is called more than once.
-  int32 ebml_header_size_;
+  int32_t ebml_header_size_;
 
   // The file position of the segment's payload.
-  int64 payload_pos_;
+  int64_t payload_pos_;
 
   // The file position of the element's size.
-  int64 size_position_;
+  int64_t size_position_;
 
   // Current DocTypeVersion (|doc_type_version_|) and that written in
   // WriteSegmentHeader().
   // WriteEbmlHeader() will be called from Finalize() if |doc_type_version_|
   // differs from |doc_type_version_written_|.
-  uint32 doc_type_version_;
-  uint32 doc_type_version_written_;
+  uint32_t doc_type_version_;
+  uint32_t doc_type_version_written_;
 
   // Pointer to the writer objects. Not owned by this class.
   IMkvWriter* writer_cluster_;
@@ -1487,6 +1690,6 @@ class Segment {
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
 };
 
-}  // end namespace mkvmuxer
+}  // namespace mkvmuxer
 
-#endif  // MKVMUXER_HPP
+#endif  // MKVMUXER_MKVMUXER_H_
similarity index 87%
rename from third_party/libwebm/mkvmuxertypes.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxertypes.h
index d0fc9fec8811a088b06773aea063b0fc860cac64..e5db121605f691d69f3b26128a2f011bc891aa7c 100644 (file)
@@ -6,25 +6,23 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#ifndef MKVMUXERTYPES_HPP
-#define MKVMUXERTYPES_HPP
-
-// Copied from Chromium basictypes.h
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);                       \
-  void operator=(const TypeName&)
+#ifndef MKVMUXER_MKVMUXERTYPES_H_
+#define MKVMUXER_MKVMUXERTYPES_H_
 
 namespace mkvmuxer {
-
 typedef unsigned char uint8;
 typedef short int16;
 typedef int int32;
 typedef unsigned int uint32;
 typedef long long int64;
 typedef unsigned long long uint64;
+}  // namespace mkvmuxer
 
-}  // end namespace mkvmuxer
+// Copied from Chromium basictypes.h
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);                       \
+  void operator=(const TypeName&)
 
-#endif  // MKVMUXERTYPES_HPP
+#endif  // MKVMUXER_MKVMUXERTYPES_HPP_
similarity index 50%
rename from third_party/libwebm/mkvmuxerutil.cpp
rename to third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
index 27ab15d51f1ed4b51e822fc07f9484ea0c32ce69..3562b8ab828e9ee9402025ed8e5da25a9b5f3868 100644 (file)
@@ -6,7 +6,7 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#include "mkvmuxerutil.hpp"
+#include "mkvmuxer/mkvmuxerutil.h"
 
 #ifdef __ANDROID__
 #include <fcntl.h>
 #include <ctime>
 #include <new>
 
-#include "mkvwriter.hpp"
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvwriter.h"
 
 namespace mkvmuxer {
 
@@ -35,64 +31,68 @@ namespace {
 // Date elements are always 8 octets in size.
 const int kDateElementSize = 8;
 
-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;
+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;
   if (frame->additional()) {
-    block_additional_elem_size = EbmlElementSize(
-        kMkvBlockAdditional, frame->additional(), frame->additional_length());
-    block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, frame->add_id());
+    block_additional_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
+                        frame->additional_length());
+    block_addid_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id());
 
     block_more_payload_size =
         block_addid_elem_size + block_additional_elem_size;
     block_more_elem_size =
-        EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
+        EbmlMasterElementSize(libwebm::kMkvBlockMore, block_more_payload_size) +
         block_more_payload_size;
     block_additions_payload_size = block_more_elem_size;
     block_additions_elem_size =
-        EbmlMasterElementSize(kMkvBlockAdditions,
+        EbmlMasterElementSize(libwebm::kMkvBlockAdditions,
                               block_additions_payload_size) +
         block_additions_payload_size;
   }
 
-  uint64 discard_padding_elem_size = 0;
+  uint64_t discard_padding_elem_size = 0;
   if (frame->discard_padding() != 0) {
     discard_padding_elem_size =
-        EbmlElementSize(kMkvDiscardPadding, frame->discard_padding());
+        EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding());
   }
 
-  const uint64 reference_block_timestamp =
+  const uint64_t reference_block_timestamp =
       frame->reference_block_timestamp() / timecode_scale;
-  uint64 reference_block_elem_size = 0;
+  uint64_t reference_block_elem_size = 0;
   if (!frame->is_key()) {
     reference_block_elem_size =
-        EbmlElementSize(kMkvReferenceBlock, reference_block_timestamp);
+        EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
   }
 
-  const uint64 duration = frame->duration() / timecode_scale;
-  uint64 block_duration_elem_size = 0;
+  const uint64_t duration = frame->duration() / timecode_scale;
+  uint64_t block_duration_elem_size = 0;
   if (duration > 0)
-    block_duration_elem_size = EbmlElementSize(kMkvBlockDuration, duration);
+    block_duration_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockDuration, duration);
 
-  const uint64 block_payload_size = 4 + frame->length();
-  const uint64 block_elem_size =
-      EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
+  const uint64_t block_payload_size = 4 + frame->length();
+  const uint64_t block_elem_size =
+      EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
+      block_payload_size;
 
-  const uint64 block_group_payload_size =
+  const uint64_t block_group_payload_size =
       block_elem_size + block_additions_elem_size + block_duration_elem_size +
       discard_padding_elem_size + reference_block_elem_size;
 
-  if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockGroup,
                               block_group_payload_size)) {
     return 0;
   }
 
-  if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
     return 0;
 
   if (WriteUInt(writer, frame->track_number()))
@@ -105,77 +105,81 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
   if (SerializeInt(writer, 0, 1))
     return 0;
 
-  if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
+  if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
     return 0;
 
   if (frame->additional()) {
-    if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
                                 block_additions_payload_size)) {
       return 0;
     }
 
-    if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
+                                block_more_payload_size))
       return 0;
 
-    if (!WriteEbmlElement(writer, kMkvBlockAddID, frame->add_id()))
+    if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id()))
       return 0;
 
-    if (!WriteEbmlElement(writer, kMkvBlockAdditional, frame->additional(),
-                          frame->additional_length())) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
+                          frame->additional(), frame->additional_length())) {
       return 0;
     }
   }
 
   if (frame->discard_padding() != 0 &&
-      !WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
+      !WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
+                        frame->discard_padding())) {
     return false;
   }
 
   if (!frame->is_key() &&
-      !WriteEbmlElement(writer, kMkvReferenceBlock,
+      !WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
                         reference_block_timestamp)) {
     return false;
   }
 
-  if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
+  if (duration > 0 &&
+      !WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
     return false;
   }
-  return EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
+  return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
+                               block_group_payload_size) +
          block_group_payload_size;
 }
 
-uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
-                        int64 timecode) {
-  if (WriteID(writer, kMkvSimpleBlock))
+uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
+                          int64_t timecode) {
+  if (WriteID(writer, libwebm::kMkvSimpleBlock))
     return 0;
 
-  const int32 size = static_cast<int32>(frame->length()) + 4;
+  const int32_t size = static_cast<int32_t>(frame->length()) + 4;
   if (WriteUInt(writer, size))
     return 0;
 
-  if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
+  if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number())))
     return 0;
 
   if (SerializeInt(writer, timecode, 2))
     return 0;
 
-  uint64 flags = 0;
+  uint64_t flags = 0;
   if (frame->is_key())
     flags |= 0x80;
 
   if (SerializeInt(writer, flags, 1))
     return 0;
 
-  if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
+  if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
     return 0;
 
-  return GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
-         frame->length();
+  return static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) +
+                               GetCodedUIntSize(size) + 4 + frame->length());
 }
 
 }  // namespace
 
-int32 GetCodedUIntSize(uint64 value) {
+int32_t GetCodedUIntSize(uint64_t value) {
   if (value < 0x000000000000007FULL)
     return 1;
   else if (value < 0x0000000000003FFFULL)
@@ -193,7 +197,7 @@ int32 GetCodedUIntSize(uint64 value) {
   return 8;
 }
 
-int32 GetUIntSize(uint64 value) {
+int32_t GetUIntSize(uint64_t value) {
   if (value < 0x0000000000000100ULL)
     return 1;
   else if (value < 0x0000000000010000ULL)
@@ -211,26 +215,26 @@ int32 GetUIntSize(uint64 value) {
   return 8;
 }
 
-int32 GetIntSize(int64 value) {
+int32_t GetIntSize(int64_t 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 v = (value < 0) ? value ^ -1LL : value;
+  const uint64_t v = (value < 0) ? value ^ -1LL : value;
   return GetUIntSize(2 * v);
 }
 
-uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
+uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) {
   // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
+  int32_t ebml_size = GetUIntSize(type);
 
   // Datasize
   ebml_size += GetCodedUIntSize(value);
 
-  return ebml_size;
+  return static_cast<uint64_t>(ebml_size);
 }
 
-uint64 EbmlElementSize(uint64 type, int64 value) {
+uint64_t EbmlElementSize(uint64_t type, int64_t value) {
   // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
+  int32_t ebml_size = GetUIntSize(type);
 
   // Datasize
   ebml_size += GetIntSize(value);
@@ -238,15 +242,20 @@ uint64 EbmlElementSize(uint64 type, int64 value) {
   // Size of Datasize
   ebml_size++;
 
-  return ebml_size;
+  return static_cast<uint64_t>(ebml_size);
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
+  return EbmlElementSize(type, value, 0);
 }
 
-uint64 EbmlElementSize(uint64 type, uint64 value) {
+uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) {
   // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
 
   // Datasize
-  ebml_size += GetUIntSize(value);
+  ebml_size +=
+      (fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value));
 
   // Size of Datasize
   ebml_size++;
@@ -254,9 +263,9 @@ uint64 EbmlElementSize(uint64 type, uint64 value) {
   return ebml_size;
 }
 
-uint64 EbmlElementSize(uint64 type, float /* value */) {
+uint64_t EbmlElementSize(uint64_t type, float /* value */) {
   // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
 
   // Datasize
   ebml_size += sizeof(float);
@@ -267,12 +276,12 @@ uint64 EbmlElementSize(uint64 type, float /* value */) {
   return ebml_size;
 }
 
-uint64 EbmlElementSize(uint64 type, const char* value) {
+uint64_t EbmlElementSize(uint64_t type, const char* value) {
   if (!value)
     return 0;
 
   // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
 
   // Datasize
   ebml_size += strlen(value);
@@ -283,12 +292,12 @@ uint64 EbmlElementSize(uint64 type, const char* value) {
   return ebml_size;
 }
 
-uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
+uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
   if (!value)
     return 0;
 
   // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
 
   // Datasize
   ebml_size += size;
@@ -299,9 +308,9 @@ uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
   return ebml_size;
 }
 
-uint64 EbmlDateElementSize(uint64 type) {
+uint64_t EbmlDateElementSize(uint64_t type) {
   // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
 
   // Datasize
   ebml_size += kDateElementSize;
@@ -312,18 +321,18 @@ uint64 EbmlDateElementSize(uint64 type) {
   return ebml_size;
 }
 
-int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
+int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
   if (!writer || size < 1 || size > 8)
     return -1;
 
-  for (int32 i = 1; i <= size; ++i) {
-    const int32 byte_count = size - i;
-    const int32 bit_count = byte_count * 8;
+  for (int32_t i = 1; i <= size; ++i) {
+    const int32_t byte_count = size - i;
+    const int32_t bit_count = byte_count * 8;
 
-    const int64 bb = value >> bit_count;
-    const uint8 b = static_cast<uint8>(bb);
+    const int64_t bb = value >> bit_count;
+    const uint8_t b = static_cast<uint8_t>(bb);
 
-    const int32 status = writer->Write(&b, 1);
+    const int32_t status = writer->Write(&b, 1);
 
     if (status < 0)
       return status;
@@ -332,26 +341,26 @@ int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
   return 0;
 }
 
-int32 SerializeFloat(IMkvWriter* writer, float f) {
+int32_t SerializeFloat(IMkvWriter* writer, float f) {
   if (!writer)
     return -1;
 
-  assert(sizeof(uint32) == sizeof(float));
+  assert(sizeof(uint32_t) == 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 u32;
+    uint32_t u32;
     float f;
   } value;
   value.f = f;
 
-  for (int32 i = 1; i <= 4; ++i) {
-    const int32 byte_count = 4 - i;
-    const int32 bit_count = byte_count * 8;
+  for (int32_t i = 1; i <= 4; ++i) {
+    const int32_t byte_count = 4 - i;
+    const int32_t bit_count = byte_count * 8;
 
-    const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
+    const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
 
-    const int32 status = writer->Write(&byte, 1);
+    const int32_t status = writer->Write(&byte, 1);
 
     if (status < 0)
       return status;
@@ -360,21 +369,21 @@ int32 SerializeFloat(IMkvWriter* writer, float f) {
   return 0;
 }
 
-int32 WriteUInt(IMkvWriter* writer, uint64 value) {
+int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
   if (!writer)
     return -1;
 
-  int32 size = GetCodedUIntSize(value);
+  int32_t size = GetCodedUIntSize(value);
 
   return WriteUIntSize(writer, value, size);
 }
 
-int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
+int32_t WriteUIntSize(IMkvWriter* writer, uint64_t value, int32_t size) {
   if (!writer || size < 0 || size > 8)
     return -1;
 
   if (size > 0) {
-    const uint64 bit = 1LL << (size * 7);
+    const uint64_t bit = 1LL << (size * 7);
 
     if (value > (bit - 2))
       return -1;
@@ -382,11 +391,11 @@ int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
     value |= bit;
   } else {
     size = 1;
-    int64 bit;
+    int64_t bit;
 
     for (;;) {
       bit = 1LL << (size * 7);
-      const uint64 max = bit - 2;
+      const uint64_t max = bit - 2;
 
       if (value <= max)
         break;
@@ -403,18 +412,18 @@ int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
   return SerializeInt(writer, value, size);
 }
 
-int32 WriteID(IMkvWriter* writer, uint64 type) {
+int32_t WriteID(IMkvWriter* writer, uint64_t type) {
   if (!writer)
     return -1;
 
   writer->ElementStartNotify(type, writer->Position());
 
-  const int32 size = GetUIntSize(type);
+  const int32_t size = GetUIntSize(type);
 
   return SerializeInt(writer, type, size);
 }
 
-bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
+bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
   if (!writer)
     return false;
 
@@ -427,41 +436,51 @@ bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
   return true;
 }
 
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value) {
+  return WriteEbmlElement(writer, type, value, 0);
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, uint64_t value,
+                      uint64_t fixed_size) {
   if (!writer)
     return false;
 
   if (WriteID(writer, type))
     return false;
 
-  const uint64 size = GetUIntSize(value);
+  uint64_t size = static_cast<uint64_t>(GetUIntSize(value));
+  if (fixed_size > 0) {
+    if (size > fixed_size)
+      return false;
+    size = fixed_size;
+  }
   if (WriteUInt(writer, size))
     return false;
 
-  if (SerializeInt(writer, value, static_cast<int32>(size)))
+  if (SerializeInt(writer, value, static_cast<int32_t>(size)))
     return false;
 
   return true;
 }
 
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
   if (!writer)
     return false;
 
   if (WriteID(writer, type))
     return 0;
 
-  const uint64 size = GetIntSize(value);
+  const uint64_t size = GetIntSize(value);
   if (WriteUInt(writer, size))
     return false;
 
-  if (SerializeInt(writer, value, static_cast<int32>(size)))
+  if (SerializeInt(writer, value, static_cast<int32_t>(size)))
     return false;
 
   return true;
 }
 
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
   if (!writer)
     return false;
 
@@ -477,25 +496,25 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
   return true;
 }
 
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
   if (!writer || !value)
     return false;
 
   if (WriteID(writer, type))
     return false;
 
-  const uint64 length = strlen(value);
+  const uint64_t length = strlen(value);
   if (WriteUInt(writer, length))
     return false;
 
-  if (writer->Write(value, static_cast<const uint32>(length)))
+  if (writer->Write(value, static_cast<const uint32_t>(length)))
     return false;
 
   return true;
 }
 
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
-                      uint64 size) {
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
+                      uint64_t size) {
   if (!writer || !value || size < 1)
     return false;
 
@@ -505,13 +524,13 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
   if (WriteUInt(writer, size))
     return false;
 
-  if (writer->Write(value, static_cast<uint32>(size)))
+  if (writer->Write(value, static_cast<uint32_t>(size)))
     return false;
 
   return true;
 }
 
-bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
+bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
   if (!writer)
     return false;
 
@@ -527,8 +546,8 @@ bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
   return true;
 }
 
-uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
-                  Cluster* cluster) {
+uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
+                    Cluster* cluster) {
   if (!writer || !frame || !frame->IsValid() || !cluster ||
       !cluster->timecode_scale())
     return 0;
@@ -537,7 +556,7 @@ uint64 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 relative_timecode = cluster->GetRelativeTimecode(
+  const int64_t relative_timecode = cluster->GetRelativeTimecode(
       frame->timestamp() / cluster->timecode_scale());
   if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
     return 0;
@@ -548,53 +567,53 @@ uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
                         cluster->timecode_scale());
 }
 
-uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
+uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
   if (!writer)
     return false;
 
   // Subtract one for the void ID and the coded size.
-  uint64 void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
-  uint64 void_size =
-      EbmlMasterElementSize(kMkvVoid, void_entry_size) + void_entry_size;
+  uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
+  uint64_t void_size =
+      EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
+      void_entry_size;
 
   if (void_size != size)
     return 0;
 
-  const int64 payload_position = writer->Position();
+  const int64_t payload_position = writer->Position();
   if (payload_position < 0)
     return 0;
 
-  if (WriteID(writer, kMkvVoid))
+  if (WriteID(writer, libwebm::kMkvVoid))
     return 0;
 
   if (WriteUInt(writer, void_entry_size))
     return 0;
 
-  const uint8 value = 0;
-  for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
+  const uint8_t value = 0;
+  for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
     if (writer->Write(&value, 1))
       return 0;
   }
 
-  const int64 stop_position = writer->Position();
+  const int64_t stop_position = writer->Position();
   if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(void_size))
+      stop_position - payload_position != static_cast<int64_t>(void_size))
     return 0;
 
   return void_size;
 }
 
-void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
+void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
+                int32_t* revision) {
   *major = 0;
   *minor = 2;
   *build = 1;
   *revision = 0;
 }
 
-}  // namespace mkvmuxer
-
-mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
-  uint64 uid = 0;
+uint64_t MakeUID(unsigned int* seed) {
+  uint64_t uid = 0;
 
 #ifdef __MINGW32__
   srand(*seed);
@@ -606,24 +625,26 @@ mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
 // TODO(fgalligan): Move random number generation to platform specific code.
 #ifdef _MSC_VER
     (void)seed;
-    const int32 nn = rand();
+    const int32_t nn = rand();
 #elif __ANDROID__
-    int32 temp_num = 1;
+    int32_t temp_num = 1;
     int fd = open("/dev/urandom", O_RDONLY);
     if (fd != -1) {
-      read(fd, &temp_num, sizeof(int32));
+      read(fd, &temp_num, sizeof(temp_num));
       close(fd);
     }
-    const int32 nn = temp_num;
+    const int32_t nn = temp_num;
 #elif defined __MINGW32__
-    const int32 nn = rand();
+    const int32_t nn = rand();
 #else
-    const int32 nn = rand_r(seed);
+    const int32_t nn = rand_r(seed);
 #endif
-    const int32 n = 0xFF & (nn >> 4);  // throw away low-order bits
+    const int32_t n = 0xFF & (nn >> 4);  // throw away low-order bits
 
     uid |= n;
   }
 
   return uid;
 }
+
+}  // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.h b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h
new file mode 100644 (file)
index 0000000..0e21a2d
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+#ifndef MKVMUXER_MKVMUXERUTIL_H_
+#define MKVMUXER_MKVMUXERUTIL_H_
+
+#include <stdint.h>
+
+namespace mkvmuxer {
+class Cluster;
+class Frame;
+class IMkvWriter;
+
+const uint64_t kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
+const int64_t kMaxBlockTimecode = 0x07FFFLL;
+
+// Writes out |value| in Big Endian order. Returns 0 on success.
+int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t 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);
+
+// 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);
+
+// 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);
+
+// 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);
+
+// Output an Mkv master element. Returns true if the element was written.
+bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t value, uint64_t 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);
+
+// 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);
+
+// 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);
+
+// 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);
+
+// 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);
+
+// 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);
+
+// 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);
+
+}  // namespace mkvmuxer
+
+#endif  // MKVMUXER_MKVMUXERUTIL_H_
similarity index 97%
rename from third_party/libwebm/mkvwriter.cpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.cc
index 75d4350c708a0da32b45e078bb32eae299f6dc94..ca48e149c6d58d4a11c5b459016479e7bfe633d3 100644 (file)
@@ -6,14 +6,12 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#include "mkvwriter.hpp"
+#include "mkvmuxer/mkvwriter.h"
 
 #ifdef _MSC_VER
 #include <share.h>  // for _SH_DENYWR
 #endif
 
-#include <new>
-
 namespace mkvmuxer {
 
 MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}
similarity index 87%
rename from third_party/libwebm/mkvwriter.hpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.h
index 684560c92d99b448d9f52df597e8c56f10c50fd3..4227c63748aa6541084eeec841ed29b327169e98 100644 (file)
@@ -6,13 +6,13 @@
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
 
-#ifndef MKVWRITER_HPP
-#define MKVWRITER_HPP
+#ifndef MKVMUXER_MKVWRITER_H_
+#define MKVMUXER_MKVWRITER_H_
 
 #include <stdio.h>
 
-#include "mkvmuxer.hpp"
-#include "mkvmuxertypes.hpp"
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvmuxertypes.h"
 
 namespace mkvmuxer {
 
@@ -46,6 +46,6 @@ class MkvWriter : public IMkvWriter {
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
 };
 
-}  // end namespace mkvmuxer
+}  // namespace mkvmuxer
 
-#endif  // MKVWRITER_HPP
+#endif  // MKVMUXER_MKVWRITER_H_
diff --git a/third_party/libwebm/mkvmuxerutil.hpp b/third_party/libwebm/mkvmuxerutil.hpp
deleted file mode 100644 (file)
index e318576..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS.  All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-#ifndef MKVMUXERUTIL_HPP
-#define MKVMUXERUTIL_HPP
-
-#include "mkvmuxer.hpp"
-#include "mkvmuxertypes.hpp"
-
-namespace mkvmuxer {
-
-class IMkvWriter;
-
-const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
-const int64 kMaxBlockTimecode = 0x07FFFLL;
-
-// Writes out |value| in Big Endian order. Returns 0 on success.
-int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
-
-// Returns the size in bytes of the element.
-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);
-
-// 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 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 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size);
-
-// Output an Mkv master element. Returns true if the element was written.
-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 WriteID(IMkvWriter* writer, uint64 type);
-
-// Output an Mkv non-master element. Returns true if the element was written.
-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 a Mkv Frame. It decides the correct element to write (Block vs
-// SimpleBlock) based on the parameters of the Frame.
-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 WriteVoidElement(IMkvWriter* writer, uint64 size);
-
-// Returns the version number of the muxer in |major|, |minor|, |build|,
-// and |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 MakeUID(unsigned int* seed);
-
-}  // end namespace mkvmuxer
-
-#endif  // MKVMUXERUTIL_HPP
similarity index 92%
rename from third_party/libwebm/mkvparser.cpp
rename to third_party/libwebm/mkvparser/mkvparser.cc
index f2855d506611c45e60973f1ce4b8cb12197f0419..21801154d9f5649515320171b14b8d38e7f181c8 100644 (file)
@@ -5,8 +5,7 @@
 // tree. An additional intellectual property rights grant can be found
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
-
-#include "mkvparser.hpp"
+#include "mkvparser/mkvparser.h"
 
 #if defined(_MSC_VER) && _MSC_VER < 1800
 #include <float.h>  // _isnan() / _finite()
 #endif
 
 #include <cassert>
+#include <cfloat>
 #include <climits>
 #include <cmath>
 #include <cstring>
+#include <memory>
 #include <new>
 
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
+#include "common/webmids.h"
 
 namespace mkvparser {
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const long long Colour::kValueNotPresent = LLONG_MAX;
 
 #ifdef MSC_COMPAT
 inline bool isnan(double val) { return !!_isnan(val); }
@@ -38,8 +36,9 @@ inline bool isinf(double val) { return std::isinf(val); }
 
 IMkvReader::~IMkvReader() {}
 
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
-                                             unsigned long long element_size) {
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+                     unsigned long long element_size) {
   if (num_elements == 0 || element_size == 0)
     return NULL;
 
@@ -350,9 +349,8 @@ long UnserializeString(IMkvReader* pReader, long long pos, long long size,
   return 0;
 }
 
-long ParseElementHeader(IMkvReader* pReader, long long& pos,
-                        long long stop, long long& id,
-                        long long& size) {
+long ParseElementHeader(IMkvReader* pReader, long long& pos, long long stop,
+                        long long& id, long long& size) {
   if (stop >= 0 && pos >= stop)
     return E_FILE_FORMAT_INVALID;
 
@@ -386,7 +384,7 @@ long ParseElementHeader(IMkvReader* pReader, long long& pos,
 
   // pos now designates payload
 
-  if (stop >= 0 && pos >= stop)
+  if (stop >= 0 && pos > stop)
     return E_FILE_FORMAT_INVALID;
 
   return 0;  // success
@@ -520,7 +518,6 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
     return status;
 
   pos = 0;
-  long long end = (available >= 1024) ? 1024 : available;
 
   // Scan until we find what looks like the first byte of the EBML header.
   const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
@@ -544,8 +541,10 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
   long len = 0;
   const long long ebml_id = ReadID(pReader, pos, len);
 
-  // TODO(tomfinegan): Move Matroska ID constants into a common namespace.
-  if (len != 4 || ebml_id != mkvmuxer::kMkvEBML)
+  if (ebml_id == E_BUFFER_NOT_FULL)
+    return E_BUFFER_NOT_FULL;
+
+  if (len != 4 || ebml_id != libwebm::kMkvEBML)
     return E_FILE_FORMAT_INVALID;
 
   // Move read pos forward to the EBML header size field.
@@ -584,7 +583,7 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
   if ((available - pos) < result)
     return pos + result;
 
-  end = pos + result;
+  const long long end = pos + result;
 
   Init();
 
@@ -599,27 +598,27 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
     if (size == 0)
       return E_FILE_FORMAT_INVALID;
 
-    if (id == mkvmuxer::kMkvEBMLVersion) {
+    if (id == libwebm::kMkvEBMLVersion) {
       m_version = UnserializeUInt(pReader, pos, size);
 
       if (m_version <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLReadVersion) {
+    } else if (id == libwebm::kMkvEBMLReadVersion) {
       m_readVersion = UnserializeUInt(pReader, pos, size);
 
       if (m_readVersion <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) {
+    } else if (id == libwebm::kMkvEBMLMaxIDLength) {
       m_maxIdLength = UnserializeUInt(pReader, pos, size);
 
       if (m_maxIdLength <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) {
+    } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
       m_maxSizeLength = UnserializeUInt(pReader, pos, size);
 
       if (m_maxSizeLength <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDocType) {
+    } else if (id == libwebm::kMkvDocType) {
       if (m_docType)
         return E_FILE_FORMAT_INVALID;
 
@@ -627,12 +626,12 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
 
       if (status)  // error
         return status;
-    } else if (id == mkvmuxer::kMkvDocTypeVersion) {
+    } else if (id == libwebm::kMkvDocTypeVersion) {
       m_docTypeVersion = UnserializeUInt(pReader, pos, size);
 
       if (m_docTypeVersion <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDocTypeReadVersion) {
+    } else if (id == libwebm::kMkvDocTypeReadVersion) {
       m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
 
       if (m_docTypeReadVersion <= 0)
@@ -650,8 +649,8 @@ long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
     return E_FILE_FORMAT_INVALID;
 
   // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
-  if (m_maxIdLength <= 0 || m_maxIdLength > 4 ||
-      m_maxSizeLength <= 0 || m_maxSizeLength > 8)
+  if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
+      m_maxSizeLength > 8)
     return E_FILE_FORMAT_INVALID;
 
   return 0;
@@ -786,7 +785,7 @@ long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
     // Handle "unknown size" for live streaming of webm files.
     const long long unknown_size = (1LL << (7 * len)) - 1;
 
-    if (id == mkvmuxer::kMkvSegment) {
+    if (id == libwebm::kMkvSegment) {
       if (size == unknown_size)
         size = -1;
 
@@ -878,7 +877,7 @@ long long Segment::ParseHeaders() {
     if (id < 0)
       return E_FILE_FORMAT_INVALID;
 
-    if (id == mkvmuxer::kMkvCluster)
+    if (id == libwebm::kMkvCluster)
       break;
 
     pos += len;  // consume ID
@@ -930,7 +929,7 @@ long long Segment::ParseHeaders() {
     if ((pos + size) > available)
       return pos + size;
 
-    if (id == mkvmuxer::kMkvInfo) {
+    if (id == libwebm::kMkvInfo) {
       if (m_pInfo)
         return E_FILE_FORMAT_INVALID;
 
@@ -944,7 +943,7 @@ long long Segment::ParseHeaders() {
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvTracks) {
+    } else if (id == libwebm::kMkvTracks) {
       if (m_pTracks)
         return E_FILE_FORMAT_INVALID;
 
@@ -958,7 +957,7 @@ long long Segment::ParseHeaders() {
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvCues) {
+    } else if (id == libwebm::kMkvCues) {
       if (m_pCues == NULL) {
         m_pCues = new (std::nothrow)
             Cues(this, pos, size, element_start, element_size);
@@ -966,7 +965,7 @@ long long Segment::ParseHeaders() {
         if (m_pCues == NULL)
           return -1;
       }
-    } else if (id == mkvmuxer::kMkvSeekHead) {
+    } else if (id == libwebm::kMkvSeekHead) {
       if (m_pSeekHead == NULL) {
         m_pSeekHead = new (std::nothrow)
             SeekHead(this, pos, size, element_start, element_size);
@@ -979,7 +978,7 @@ long long Segment::ParseHeaders() {
         if (status)
           return status;
       }
-    } else if (id == mkvmuxer::kMkvChapters) {
+    } else if (id == libwebm::kMkvChapters) {
       if (m_pChapters == NULL) {
         m_pChapters = new (std::nothrow)
             Chapters(this, pos, size, element_start, element_size);
@@ -992,7 +991,7 @@ long long Segment::ParseHeaders() {
         if (status)
           return status;
       }
-    } else if (id == mkvmuxer::kMkvTags) {
+    } else if (id == libwebm::kMkvTags) {
       if (m_pTags == NULL) {
         m_pTags = new (std::nothrow)
             Tags(this, pos, size, element_start, element_size);
@@ -1131,7 +1130,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
       return E_FILE_FORMAT_INVALID;
     }
 
-    if (id == mkvmuxer::kMkvCues) {
+    if (id == libwebm::kMkvCues) {
       if (size == unknown_size) {
         // Cues element of unknown size: Not supported.
         return E_FILE_FORMAT_INVALID;
@@ -1149,7 +1148,7 @@ long Segment::DoLoadCluster(long long& pos, long& len) {
       continue;
     }
 
-    if (id != mkvmuxer::kMkvCluster) {
+    if (id != libwebm::kMkvCluster) {
       // Besides the Segment, Libwebm allows only cluster elements of unknown
       // size. Fail the parse upon encountering a non-cluster element reporting
       // unknown size.
@@ -1466,7 +1465,7 @@ long Segment::Load() {
     return E_FILE_FORMAT_INVALID;
 
   for (;;) {
-    const int status = LoadCluster();
+    const long status = LoadCluster();
 
     if (status < 0)  // error
       return status;
@@ -1512,9 +1511,9 @@ long SeekHead::Parse() {
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvSeek)
+    if (id == libwebm::kMkvSeek)
       ++entry_count;
-    else if (id == mkvmuxer::kMkvVoid)
+    else if (id == libwebm::kMkvVoid)
       ++void_element_count;
 
     pos += size;  // consume payload
@@ -1553,14 +1552,14 @@ long SeekHead::Parse() {
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvSeek) {
+    if (id == libwebm::kMkvSeek) {
       if (ParseEntry(pReader, pos, size, pEntry)) {
         Entry& e = *pEntry++;
 
         e.element_start = idpos;
         e.element_size = (pos + size) - idpos;
       }
-    } else if (id == mkvmuxer::kMkvVoid) {
+    } else if (id == libwebm::kMkvVoid) {
       VoidElement& e = *pVoidElement++;
 
       e.element_start = idpos;
@@ -1664,7 +1663,7 @@ long Segment::ParseCues(long long off, long long& pos, long& len) {
 
   const long long id = ReadID(m_pReader, idpos, len);
 
-  if (id != mkvmuxer::kMkvCues)
+  if (id != libwebm::kMkvCues)
     return E_FILE_FORMAT_INVALID;
 
   pos += len;  // consume ID
@@ -1746,7 +1745,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
   if (seekIdId < 0)
     return false;
 
-  if (seekIdId != mkvmuxer::kMkvSeekID)
+  if (seekIdId != libwebm::kMkvSeekID)
     return false;
 
   if ((pos + len) > stop)
@@ -1790,7 +1789,7 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
 
   const long long seekPosId = ReadID(pReader, pos, len);
 
-  if (seekPosId != mkvmuxer::kMkvSeekPosition)
+  if (seekPosId != libwebm::kMkvSeekPosition)
     return false;
 
   if ((pos + len) > stop)
@@ -1900,7 +1899,7 @@ bool Cues::Init() const {
       return false;
     }
 
-    if (id == mkvmuxer::kMkvCuePoint) {
+    if (id == libwebm::kMkvCuePoint) {
       if (!PreloadCuePoint(cue_points_size, idpos))
         return false;
     }
@@ -1975,7 +1974,7 @@ bool Cues::LoadCuePoint() const {
     if ((m_pos + size) > stop)
       return false;
 
-    if (id != mkvmuxer::kMkvCuePoint) {
+    if (id != libwebm::kMkvCuePoint) {
       m_pos += size;  // consume payload
       if (m_pos > stop)
         return false;
@@ -2105,8 +2104,8 @@ const CuePoint* Cues::GetLast() const {
 }
 
 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
-  if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
-      m_cue_points == NULL || m_count < 1) {
+  if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
+      m_count < 1) {
     return NULL;
   }
 
@@ -2286,7 +2285,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
     long len;
 
     const long long id = ReadID(pReader, pos_, len);
-    if (id != mkvmuxer::kMkvCuePoint)
+    if (id != libwebm::kMkvCuePoint)
       return false;
 
     pos_ += len;  // consume ID
@@ -2326,10 +2325,10 @@ bool CuePoint::Load(IMkvReader* pReader) {
       return false;
     }
 
-    if (id == mkvmuxer::kMkvCueTime)
+    if (id == libwebm::kMkvCueTime)
       m_timecode = UnserializeUInt(pReader, pos, size);
 
-    else if (id == mkvmuxer::kMkvCueTrackPositions)
+    else if (id == libwebm::kMkvCueTrackPositions)
       ++m_track_positions_count;
 
     pos += size;  // consume payload
@@ -2368,7 +2367,7 @@ bool CuePoint::Load(IMkvReader* pReader) {
     pos += len;  // consume Size field
     assert((pos + size) <= stop);
 
-    if (id == mkvmuxer::kMkvCueTrackPositions) {
+    if (id == libwebm::kMkvCueTrackPositions) {
       TrackPosition& tp = *p++;
       if (!tp.Parse(pReader, pos, size)) {
         return false;
@@ -2417,11 +2416,11 @@ bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
       return false;
     }
 
-    if (id == mkvmuxer::kMkvCueTrack)
+    if (id == libwebm::kMkvCueTrack)
       m_track = UnserializeUInt(pReader, pos, size);
-    else if (id == mkvmuxer::kMkvCueClusterPosition)
+    else if (id == libwebm::kMkvCueClusterPosition)
       m_pos = UnserializeUInt(pReader, pos, size);
-    else if (id == mkvmuxer::kMkvCueBlockNumber)
+    else if (id == libwebm::kMkvCueBlockNumber)
       m_block = UnserializeUInt(pReader, pos, size);
 
     pos += size;  // consume payload
@@ -2555,7 +2554,7 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
       return NULL;
 
     const long long id = ReadID(m_pReader, pos, len);
-    if (id != mkvmuxer::kMkvCluster)
+    if (id != libwebm::kMkvCluster)
       return NULL;
 
     pos += len;  // consume ID
@@ -2612,7 +2611,7 @@ const Cluster* Segment::GetNext(const Cluster* pCurr) {
     if (size == 0)  // weird
       continue;
 
-    if (id == mkvmuxer::kMkvCluster) {
+    if (id == libwebm::kMkvCluster) {
       const long long off_next_ = idpos - m_start;
 
       long long pos_;
@@ -2762,7 +2761,7 @@ long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
 
     const long long id = ReadUInt(m_pReader, pos, len);
 
-    if (id != mkvmuxer::kMkvCluster)
+    if (id != libwebm::kMkvCluster)
       return -1;
 
     pos += len;  // consume ID
@@ -2927,7 +2926,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
       return E_FILE_FORMAT_INVALID;
     }
 
-    if (id == mkvmuxer::kMkvCues) {
+    if (id == libwebm::kMkvCues) {
       if (size == unknown_size)
         return E_FILE_FORMAT_INVALID;
 
@@ -2953,7 +2952,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
       continue;
     }
 
-    if (id != mkvmuxer::kMkvCluster) {  // not a Cluster ID
+    if (id != libwebm::kMkvCluster) {  // not a Cluster ID
       if (size == unknown_size)
         return E_FILE_FORMAT_INVALID;
 
@@ -3091,7 +3090,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
       // that we have exhausted the sub-element's inside the cluster
       // whose ID we parsed earlier.
 
-      if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues)
+      if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
         break;
 
       pos += len;  // consume ID (of sub-element)
@@ -3259,7 +3258,7 @@ long Chapters::Parse() {
     if (size == 0)  // weird
       continue;
 
-    if (id == mkvmuxer::kMkvEditionEntry) {
+    if (id == libwebm::kMkvEditionEntry) {
       status = ParseEdition(pos, size);
 
       if (status < 0)  // error
@@ -3375,7 +3374,7 @@ long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
     if (size == 0)
       continue;
 
-    if (id == mkvmuxer::kMkvChapterAtom) {
+    if (id == libwebm::kMkvChapterAtom) {
       status = ParseAtom(pReader, pos, size);
 
       if (status < 0)  // error
@@ -3508,17 +3507,17 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
     if (size == 0)  // 0 length payload, skip.
       continue;
 
-    if (id == mkvmuxer::kMkvChapterDisplay) {
+    if (id == libwebm::kMkvChapterDisplay) {
       status = ParseDisplay(pReader, pos, size);
 
       if (status < 0)  // error
         return status;
-    } else if (id == mkvmuxer::kMkvChapterStringUID) {
+    } else if (id == libwebm::kMkvChapterStringUID) {
       status = UnserializeString(pReader, pos, size, m_string_uid);
 
       if (status < 0)  // error
         return status;
-    } else if (id == mkvmuxer::kMkvChapterUID) {
+    } else if (id == libwebm::kMkvChapterUID) {
       long long val;
       status = UnserializeInt(pReader, pos, size, val);
 
@@ -3526,14 +3525,14 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
         return status;
 
       m_uid = static_cast<unsigned long long>(val);
-    } else if (id == mkvmuxer::kMkvChapterTimeStart) {
+    } else if (id == libwebm::kMkvChapterTimeStart) {
       const long long val = UnserializeUInt(pReader, pos, size);
 
       if (val < 0)  // error
         return static_cast<long>(val);
 
       m_start_timecode = val;
-    } else if (id == mkvmuxer::kMkvChapterTimeEnd) {
+    } else if (id == libwebm::kMkvChapterTimeEnd) {
       const long long val = UnserializeUInt(pReader, pos, size);
 
       if (val < 0)  // error
@@ -3661,17 +3660,17 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
     if (size == 0)  // No payload.
       continue;
 
-    if (id == mkvmuxer::kMkvChapString) {
+    if (id == libwebm::kMkvChapString) {
       status = UnserializeString(pReader, pos, size, m_string);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvChapLanguage) {
+    } else if (id == libwebm::kMkvChapLanguage) {
       status = UnserializeString(pReader, pos, size, m_language);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvChapCountry) {
+    } else if (id == libwebm::kMkvChapCountry) {
       status = UnserializeString(pReader, pos, size, m_country);
 
       if (status)
@@ -3724,7 +3723,7 @@ long Tags::Parse() {
     if (size == 0)  // 0 length tag, read another
       continue;
 
-    if (id == mkvmuxer::kMkvTag) {
+    if (id == libwebm::kMkvTag) {
       status = ParseTag(pos, size);
 
       if (status < 0)
@@ -3840,7 +3839,7 @@ long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
     if (size == 0)  // 0 length tag, read another
       continue;
 
-    if (id == mkvmuxer::kMkvSimpleTag) {
+    if (id == libwebm::kMkvSimpleTag) {
       status = ParseSimpleTag(pReader, pos, size);
 
       if (status < 0)
@@ -3931,12 +3930,12 @@ long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
     if (size == 0)  // weird
       continue;
 
-    if (id == mkvmuxer::kMkvTagName) {
+    if (id == libwebm::kMkvTagName) {
       status = UnserializeString(pReader, pos, size, m_tag_name);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvTagString) {
+    } else if (id == libwebm::kMkvTagString) {
       status = UnserializeString(pReader, pos, size, m_tag_string);
 
       if (status)
@@ -3996,12 +3995,12 @@ long SegmentInfo::Parse() {
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvTimecodeScale) {
+    if (id == libwebm::kMkvTimecodeScale) {
       m_timecodeScale = UnserializeUInt(pReader, pos, size);
 
       if (m_timecodeScale <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDuration) {
+    } else if (id == libwebm::kMkvDuration) {
       const long status = UnserializeFloat(pReader, pos, size, m_duration);
 
       if (status < 0)
@@ -4009,19 +4008,19 @@ long SegmentInfo::Parse() {
 
       if (m_duration < 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvMuxingApp) {
+    } else if (id == libwebm::kMkvMuxingApp) {
       const long status =
           UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvWritingApp) {
+    } else if (id == libwebm::kMkvWritingApp) {
       const long status =
           UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvTitle) {
+    } else if (id == libwebm::kMkvTitle) {
       const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
 
       if (status)
@@ -4176,7 +4175,7 @@ long ContentEncoding::ParseContentEncAESSettingsEntry(
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvAESSettingsCipherMode) {
+    if (id == libwebm::kMkvAESSettingsCipherMode) {
       aes->cipher_mode = UnserializeUInt(pReader, pos, size);
       if (aes->cipher_mode != 1)
         return E_FILE_FORMAT_INVALID;
@@ -4207,10 +4206,10 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvContentCompression)
+    if (id == libwebm::kMkvContentCompression)
       ++compression_count;
 
-    if (id == mkvmuxer::kMkvContentEncryption)
+    if (id == libwebm::kMkvContentEncryption)
       ++encryption_count;
 
     pos += size;  // consume payload
@@ -4246,15 +4245,15 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvContentEncodingOrder) {
+    if (id == libwebm::kMkvContentEncodingOrder) {
       encoding_order_ = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentEncodingScope) {
+    } else if (id == libwebm::kMkvContentEncodingScope) {
       encoding_scope_ = UnserializeUInt(pReader, pos, size);
       if (encoding_scope_ < 1)
         return -1;
-    } else if (id == mkvmuxer::kMkvContentEncodingType) {
+    } else if (id == libwebm::kMkvContentEncodingType) {
       encoding_type_ = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentCompression) {
+    } else if (id == libwebm::kMkvContentCompression) {
       ContentCompression* const compression =
           new (std::nothrow) ContentCompression();
       if (!compression)
@@ -4266,7 +4265,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
         return status;
       }
       *compression_entries_end_++ = compression;
-    } else if (id == mkvmuxer::kMkvContentEncryption) {
+    } else if (id == libwebm::kMkvContentEncryption) {
       ContentEncryption* const encryption =
           new (std::nothrow) ContentEncryption();
       if (!encryption)
@@ -4307,13 +4306,13 @@ long ContentEncoding::ParseCompressionEntry(long long start, long long size,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvContentCompAlgo) {
+    if (id == libwebm::kMkvContentCompAlgo) {
       long long algo = UnserializeUInt(pReader, pos, size);
       if (algo < 0)
         return E_FILE_FORMAT_INVALID;
       compression->algo = algo;
       valid = true;
-    } else if (id == mkvmuxer::kMkvContentCompSettings) {
+    } else if (id == libwebm::kMkvContentCompSettings) {
       if (size <= 0)
         return E_FILE_FORMAT_INVALID;
 
@@ -4360,11 +4359,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvContentEncAlgo) {
+    if (id == libwebm::kMkvContentEncAlgo) {
       encryption->algo = UnserializeUInt(pReader, pos, size);
       if (encryption->algo != 5)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvContentEncKeyID) {
+    } else if (id == libwebm::kMkvContentEncKeyID) {
       delete[] encryption->key_id;
       encryption->key_id = NULL;
       encryption->key_id_len = 0;
@@ -4386,7 +4385,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
 
       encryption->key_id = buf;
       encryption->key_id_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSignature) {
+    } else if (id == libwebm::kMkvContentSignature) {
       delete[] encryption->signature;
       encryption->signature = NULL;
       encryption->signature_len = 0;
@@ -4408,7 +4407,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
 
       encryption->signature = buf;
       encryption->signature_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSigKeyID) {
+    } else if (id == libwebm::kMkvContentSigKeyID) {
       delete[] encryption->sig_key_id;
       encryption->sig_key_id = NULL;
       encryption->sig_key_id_len = 0;
@@ -4430,11 +4429,11 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
 
       encryption->sig_key_id = buf;
       encryption->sig_key_id_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSigAlgo) {
+    } else if (id == libwebm::kMkvContentSigAlgo) {
       encryption->sig_algo = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentSigHashAlgo) {
+    } else if (id == libwebm::kMkvContentSigHashAlgo) {
       encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentEncAESSettings) {
+    } else if (id == libwebm::kMkvContentEncAESSettings) {
       const long status = ParseContentEncAESSettingsEntry(
           pos, size, pReader, &encryption->aes_settings);
       if (status)
@@ -4921,7 +4920,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
       return status;
 
     // pos now designates start of element
-    if (id == mkvmuxer::kMkvContentEncoding)
+    if (id == libwebm::kMkvContentEncoding)
       ++count;
 
     pos += size;  // consume payload
@@ -4946,7 +4945,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) {
       return status;
 
     // pos now designates start of element
-    if (id == mkvmuxer::kMkvContentEncoding) {
+    if (id == libwebm::kMkvContentEncoding) {
       ContentEncoding* const content_encoding =
           new (std::nothrow) ContentEncoding();
       if (!content_encoding)
@@ -4978,9 +4977,222 @@ BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
 
 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
 
+bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
+                                long long value_size, bool is_x,
+                                PrimaryChromaticity** chromaticity) {
+  if (!reader)
+    return false;
+
+  std::auto_ptr<PrimaryChromaticity> chromaticity_ptr;
+
+  if (!*chromaticity) {
+    chromaticity_ptr.reset(new PrimaryChromaticity());
+  } else {
+    chromaticity_ptr.reset(*chromaticity);
+  }
+
+  if (!chromaticity_ptr.get())
+    return false;
+
+  float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
+
+  double parser_value = 0;
+  const long long value_parse_status =
+      UnserializeFloat(reader, read_pos, value_size, parser_value);
+
+  *value = static_cast<float>(parser_value);
+
+  if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
+    return false;
+
+  *chromaticity = chromaticity_ptr.release();
+  return true;
+}
+
+bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
+                              long long mm_size, MasteringMetadata** mm) {
+  if (!reader || *mm)
+    return false;
+
+  std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+  if (!mm_ptr.get())
+    return false;
+
+  const long long mm_end = mm_start + mm_size;
+  long long read_pos = mm_start;
+
+  while (read_pos < mm_end) {
+    long long child_id = 0;
+    long long child_size = 0;
+
+    const long long status =
+        ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
+    if (status < 0)
+      return false;
+
+    if (child_id == libwebm::kMkvLuminanceMax) {
+      double value = 0;
+      const long long value_parse_status =
+          UnserializeFloat(reader, read_pos, child_size, value);
+      mm_ptr->luminance_max = static_cast<float>(value);
+      if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
+          mm_ptr->luminance_max > 9999.99) {
+        return false;
+      }
+    } else if (child_id == libwebm::kMkvLuminanceMin) {
+      double value = 0;
+      const long long value_parse_status =
+          UnserializeFloat(reader, read_pos, child_size, value);
+      mm_ptr->luminance_min = static_cast<float>(value);
+      if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
+          mm_ptr->luminance_min > 999.9999) {
+        return false;
+      }
+    } else {
+      bool is_x = false;
+      PrimaryChromaticity** chromaticity;
+      switch (child_id) {
+        case libwebm::kMkvPrimaryRChromaticityX:
+        case libwebm::kMkvPrimaryRChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
+          chromaticity = &mm_ptr->r;
+          break;
+        case libwebm::kMkvPrimaryGChromaticityX:
+        case libwebm::kMkvPrimaryGChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
+          chromaticity = &mm_ptr->g;
+          break;
+        case libwebm::kMkvPrimaryBChromaticityX:
+        case libwebm::kMkvPrimaryBChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
+          chromaticity = &mm_ptr->b;
+          break;
+        case libwebm::kMkvWhitePointChromaticityX:
+        case libwebm::kMkvWhitePointChromaticityY:
+          is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
+          chromaticity = &mm_ptr->white_point;
+          break;
+        default:
+          return false;
+      }
+      const bool value_parse_status = PrimaryChromaticity::Parse(
+          reader, read_pos, child_size, is_x, chromaticity);
+      if (!value_parse_status)
+        return false;
+    }
+
+    read_pos += child_size;
+    if (read_pos > mm_end)
+      return false;
+  }
+
+  *mm = mm_ptr.release();
+  return true;
+}
+
+bool Colour::Parse(IMkvReader* reader, long long colour_start,
+                   long long colour_size, Colour** colour) {
+  if (!reader || *colour)
+    return false;
+
+  std::auto_ptr<Colour> colour_ptr(new Colour());
+  if (!colour_ptr.get())
+    return false;
+
+  const long long colour_end = colour_start + colour_size;
+  long long read_pos = colour_start;
+
+  while (read_pos < colour_end) {
+    long long child_id = 0;
+    long long child_size = 0;
+
+    const long status =
+        ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
+    if (status < 0)
+      return false;
+
+    if (child_id == libwebm::kMkvMatrixCoefficients) {
+      colour_ptr->matrix_coefficients =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->matrix_coefficients < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvBitsPerChannel) {
+      colour_ptr->bits_per_channel =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->bits_per_channel < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
+      colour_ptr->chroma_subsampling_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_subsampling_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
+      colour_ptr->chroma_subsampling_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_subsampling_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
+      colour_ptr->cb_subsampling_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->cb_subsampling_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
+      colour_ptr->cb_subsampling_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->cb_subsampling_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSitingHorz) {
+      colour_ptr->chroma_siting_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_siting_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSitingVert) {
+      colour_ptr->chroma_siting_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_siting_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvRange) {
+      colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->range < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvTransferCharacteristics) {
+      colour_ptr->transfer_characteristics =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->transfer_characteristics < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvPrimaries) {
+      colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->primaries < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMaxCLL) {
+      colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->max_cll < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMaxFALL) {
+      colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->max_fall < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMasteringMetadata) {
+      if (!MasteringMetadata::Parse(reader, read_pos, child_size,
+                                    &colour_ptr->mastering_metadata))
+        return false;
+    } else {
+      return false;
+    }
+
+    read_pos += child_size;
+    if (read_pos > colour_end)
+      return false;
+  }
+  *colour = colour_ptr.release();
+  return true;
+}
+
 VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
                        long long element_size)
-    : Track(pSegment, element_start, element_size) {}
+    : Track(pSegment, element_start, element_size), m_colour(NULL) {}
+
+VideoTrack::~VideoTrack() { delete m_colour; }
 
 long VideoTrack::Parse(Segment* pSegment, const Info& info,
                        long long element_start, long long element_size,
@@ -5011,6 +5223,8 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
 
   const long long stop = pos + s.size;
 
+  Colour* colour = NULL;
+
   while (pos < stop) {
     long long id, size;
 
@@ -5019,37 +5233,37 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvPixelWidth) {
+    if (id == libwebm::kMkvPixelWidth) {
       width = UnserializeUInt(pReader, pos, size);
 
       if (width <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvPixelHeight) {
+    } else if (id == libwebm::kMkvPixelHeight) {
       height = UnserializeUInt(pReader, pos, size);
 
       if (height <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayWidth) {
+    } else if (id == libwebm::kMkvDisplayWidth) {
       display_width = UnserializeUInt(pReader, pos, size);
 
       if (display_width <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayHeight) {
+    } else if (id == libwebm::kMkvDisplayHeight) {
       display_height = UnserializeUInt(pReader, pos, size);
 
       if (display_height <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayUnit) {
+    } else if (id == libwebm::kMkvDisplayUnit) {
       display_unit = UnserializeUInt(pReader, pos, size);
 
       if (display_unit < 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvStereoMode) {
+    } else if (id == libwebm::kMkvStereoMode) {
       stereo_mode = UnserializeUInt(pReader, pos, size);
 
       if (stereo_mode < 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvFrameRate) {
+    } else if (id == libwebm::kMkvFrameRate) {
       const long status = UnserializeFloat(pReader, pos, size, rate);
 
       if (status < 0)
@@ -5057,6 +5271,9 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
 
       if (rate <= 0)
         return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvColour) {
+      if (!Colour::Parse(pReader, pos, size, &colour))
+        return E_FILE_FORMAT_INVALID;
     }
 
     pos += size;  // consume payload
@@ -5087,6 +5304,7 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info,
   pTrack->m_display_unit = display_unit;
   pTrack->m_stereo_mode = stereo_mode;
   pTrack->m_rate = rate;
+  pTrack->m_colour = colour;
 
   pResult = pTrack;
   return 0;  // success
@@ -5185,6 +5403,8 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
   return 0;
 }
 
+Colour* VideoTrack::GetColour() const { return m_colour; }
+
 long long VideoTrack::GetWidth() const { return m_width; }
 
 long long VideoTrack::GetHeight() const { return m_height; }
@@ -5239,7 +5459,7 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
     if (status < 0)  // error
       return status;
 
-    if (id == mkvmuxer::kMkvSamplingFrequency) {
+    if (id == libwebm::kMkvSamplingFrequency) {
       status = UnserializeFloat(pReader, pos, size, rate);
 
       if (status < 0)
@@ -5247,12 +5467,12 @@ long AudioTrack::Parse(Segment* pSegment, const Info& info,
 
       if (rate <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvChannels) {
+    } else if (id == libwebm::kMkvChannels) {
       channels = UnserializeUInt(pReader, pos, size);
 
       if (channels <= 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvBitDepth) {
+    } else if (id == libwebm::kMkvBitDepth) {
       bit_depth = UnserializeUInt(pReader, pos, size);
 
       if (bit_depth <= 0)
@@ -5325,7 +5545,7 @@ long Tracks::Parse() {
     if (size == 0)  // weird
       continue;
 
-    if (id == mkvmuxer::kMkvTrackEntry)
+    if (id == libwebm::kMkvTrackEntry)
       ++count;
 
     pos += size;  // consume payload
@@ -5367,7 +5587,7 @@ long Tracks::Parse() {
 
     const long long element_size = payload_stop - element_start;
 
-    if (id == mkvmuxer::kMkvTrackEntry) {
+    if (id == libwebm::kMkvTrackEntry) {
       Track*& pTrack = *m_trackEntriesEnd;
       pTrack = NULL;
 
@@ -5443,16 +5663,16 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
 
     const long long start = pos;
 
-    if (id == mkvmuxer::kMkvVideo) {
+    if (id == libwebm::kMkvVideo) {
       v.start = start;
       v.size = size;
-    } else if (id == mkvmuxer::kMkvAudio) {
+    } else if (id == libwebm::kMkvAudio) {
       a.start = start;
       a.size = size;
-    } else if (id == mkvmuxer::kMkvContentEncodings) {
+    } else if (id == libwebm::kMkvContentEncodings) {
       e.start = start;
       e.size = size;
-    } else if (id == mkvmuxer::kMkvTrackUID) {
+    } else if (id == libwebm::kMkvTrackUID) {
       if (size > 8)
         return E_FILE_FORMAT_INVALID;
 
@@ -5474,49 +5694,49 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
 
         ++pos_;
       }
-    } else if (id == mkvmuxer::kMkvTrackNumber) {
+    } else if (id == libwebm::kMkvTrackNumber) {
       const long long num = UnserializeUInt(pReader, pos, size);
 
       if ((num <= 0) || (num > 127))
         return E_FILE_FORMAT_INVALID;
 
       info.number = static_cast<long>(num);
-    } else if (id == mkvmuxer::kMkvTrackType) {
+    } else if (id == libwebm::kMkvTrackType) {
       const long long type = UnserializeUInt(pReader, pos, size);
 
       if ((type <= 0) || (type > 254))
         return E_FILE_FORMAT_INVALID;
 
       info.type = static_cast<long>(type);
-    } else if (id == mkvmuxer::kMkvName) {
+    } else if (id == libwebm::kMkvName) {
       const long status =
           UnserializeString(pReader, pos, size, info.nameAsUTF8);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvLanguage) {
+    } else if (id == libwebm::kMkvLanguage) {
       const long status = UnserializeString(pReader, pos, size, info.language);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvDefaultDuration) {
+    } else if (id == libwebm::kMkvDefaultDuration) {
       const long long duration = UnserializeUInt(pReader, pos, size);
 
       if (duration < 0)
         return E_FILE_FORMAT_INVALID;
 
       info.defaultDuration = static_cast<unsigned long long>(duration);
-    } else if (id == mkvmuxer::kMkvCodecID) {
+    } else if (id == libwebm::kMkvCodecID) {
       const long status = UnserializeString(pReader, pos, size, info.codecId);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvFlagLacing) {
+    } else if (id == libwebm::kMkvFlagLacing) {
       lacing = UnserializeUInt(pReader, pos, size);
 
       if ((lacing < 0) || (lacing > 1))
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvCodecPrivate) {
+    } else if (id == libwebm::kMkvCodecPrivate) {
       delete[] info.codecPrivate;
       info.codecPrivate = NULL;
       info.codecPrivateSize = 0;
@@ -5539,15 +5759,15 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size,
         info.codecPrivate = buf;
         info.codecPrivateSize = buflen;
       }
-    } else if (id == mkvmuxer::kMkvCodecName) {
+    } else if (id == libwebm::kMkvCodecName) {
       const long status =
           UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
 
       if (status)
         return status;
-    } else if (id == mkvmuxer::kMkvCodecDelay) {
+    } else if (id == libwebm::kMkvCodecDelay) {
       info.codecDelay = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvSeekPreRoll) {
+    } else if (id == libwebm::kMkvSeekPreRoll) {
       info.seekPreRoll = UnserializeUInt(pReader, pos, size);
     }
 
@@ -5730,7 +5950,7 @@ long Cluster::Load(long long& pos, long& len) const {
   if (id_ < 0)  // error
     return static_cast<long>(id_);
 
-  if (id_ != mkvmuxer::kMkvCluster)
+  if (id_ != libwebm::kMkvCluster)
     return E_FILE_FORMAT_INVALID;
 
   pos += len;  // consume id
@@ -5812,10 +6032,10 @@ long Cluster::Load(long long& pos, long& len) const {
     // that we have exhausted the sub-element's inside the cluster
     // whose ID we parsed earlier.
 
-    if (id == mkvmuxer::kMkvCluster)
+    if (id == libwebm::kMkvCluster)
       break;
 
-    if (id == mkvmuxer::kMkvCues)
+    if (id == libwebm::kMkvCues)
       break;
 
     pos += len;  // consume ID field
@@ -5864,7 +6084,7 @@ long Cluster::Load(long long& pos, long& len) const {
     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
       return E_FILE_FORMAT_INVALID;
 
-    if (id == mkvmuxer::kMkvTimecode) {
+    if (id == libwebm::kMkvTimecode) {
       len = static_cast<long>(size);
 
       if ((pos + size) > avail)
@@ -5879,10 +6099,10 @@ long Cluster::Load(long long& pos, long& len) const {
 
       if (bBlock)
         break;
-    } else if (id == mkvmuxer::kMkvBlockGroup) {
+    } else if (id == libwebm::kMkvBlockGroup) {
       bBlock = true;
       break;
-    } else if (id == mkvmuxer::kMkvSimpleBlock) {
+    } else if (id == libwebm::kMkvSimpleBlock) {
       bBlock = true;
       break;
     }
@@ -5980,7 +6200,7 @@ long Cluster::Parse(long long& pos, long& len) const {
     // that we have exhausted the sub-element's inside the cluster
     // whose ID we parsed earlier.
 
-    if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) {
+    if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
       if (m_element_size < 0)
         m_element_size = pos - m_element_start;
 
@@ -6035,8 +6255,7 @@ long Cluster::Parse(long long& pos, long& len) const {
 
     if (cluster_stop >= 0) {
       if (block_stop > cluster_stop) {
-        if (id == mkvmuxer::kMkvBlockGroup ||
-            id == mkvmuxer::kMkvSimpleBlock) {
+        if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
           return E_FILE_FORMAT_INVALID;
         }
 
@@ -6054,10 +6273,10 @@ long Cluster::Parse(long long& pos, long& len) const {
 
     Cluster* const this_ = const_cast<Cluster*>(this);
 
-    if (id == mkvmuxer::kMkvBlockGroup)
+    if (id == libwebm::kMkvBlockGroup)
       return this_->ParseBlockGroup(size, pos, len);
 
-    if (id == mkvmuxer::kMkvSimpleBlock)
+    if (id == libwebm::kMkvSimpleBlock)
       return this_->ParseSimpleBlock(size, pos, len);
 
     pos += size;  // consume payload
@@ -6188,8 +6407,7 @@ long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
     return E_BUFFER_NOT_FULL;
   }
 
-  status = CreateBlock(mkvmuxer::kMkvSimpleBlock,
-                       block_start, block_size,
+  status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
                        0);  // DiscardPadding
 
   if (status != 0)
@@ -6299,14 +6517,14 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
     if (size == unknown_size)
       return E_FILE_FORMAT_INVALID;
 
-    if (id == mkvmuxer::kMkvDiscardPadding) {
+    if (id == libwebm::kMkvDiscardPadding) {
       status = UnserializeInt(pReader, pos, size, discard_padding);
 
       if (status < 0)  // error
         return status;
     }
 
-    if (id != mkvmuxer::kMkvBlock) {
+    if (id != libwebm::kMkvBlock) {
       pos += size;  // consume sub-part of block group
 
       if (pos > payload_stop)
@@ -6399,8 +6617,8 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
   if (pos != payload_stop)
     return E_FILE_FORMAT_INVALID;
 
-  status = CreateBlock(mkvmuxer::kMkvBlockGroup,
-                       payload_start, payload_size, discard_padding);
+  status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
+                       discard_padding);
   if (status != 0)
     return status;
 
@@ -6565,7 +6783,7 @@ long Cluster::HasBlockEntries(
     if (id < 0)  // error
       return static_cast<long>(id);
 
-    if (id != mkvmuxer::kMkvCluster)
+    if (id != libwebm::kMkvCluster)
       return E_PARSE_FAILED;
 
     pos += len;  // consume Cluster ID field
@@ -6653,10 +6871,10 @@ long Cluster::HasBlockEntries(
     // that we have exhausted the sub-element's inside the cluster
     // whose ID we parsed earlier.
 
-    if (id == mkvmuxer::kMkvCluster)
+    if (id == libwebm::kMkvCluster)
       return 0;  // no entries found
 
-    if (id == mkvmuxer::kMkvCues)
+    if (id == libwebm::kMkvCues)
       return 0;  // no entries found
 
     pos += len;  // consume id field
@@ -6708,10 +6926,10 @@ long Cluster::HasBlockEntries(
     if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
       return E_FILE_FORMAT_INVALID;
 
-    if (id == mkvmuxer::kMkvBlockGroup)
+    if (id == libwebm::kMkvBlockGroup)
       return 1;  // have at least one entry
 
-    if (id == mkvmuxer::kMkvSimpleBlock)
+    if (id == libwebm::kMkvSimpleBlock)
       return 1;  // have at least one entry
 
     pos += size;  // consume payload
@@ -6786,7 +7004,7 @@ long long Cluster::GetLastTime() const {
 long Cluster::CreateBlock(long long id,
                           long long pos,  // absolute pos of payload
                           long long size, long long discard_padding) {
-  if (id != mkvmuxer::kMkvBlockGroup && id != mkvmuxer::kMkvSimpleBlock)
+  if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
     return E_PARSE_FAILED;
 
   if (m_entries_count < 0) {  // haven't parsed anything yet
@@ -6826,7 +7044,7 @@ long Cluster::CreateBlock(long long id,
     }
   }
 
-  if (id == mkvmuxer::kMkvBlockGroup)
+  if (id == libwebm::kMkvBlockGroup)
     return CreateBlockGroup(pos, size, discard_padding);
   else
     return CreateSimpleBlock(pos, size);
@@ -6871,12 +7089,12 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
 
     pos += len;  // consume size
 
-    if (id == mkvmuxer::kMkvBlock) {
+    if (id == libwebm::kMkvBlock) {
       if (bpos < 0) {  // Block ID
         bpos = pos;
         bsize = size;
       }
-    } else if (id == mkvmuxer::kMkvBlockDuration) {
+    } else if (id == libwebm::kMkvBlockDuration) {
       if (size > 8)
         return E_FILE_FORMAT_INVALID;
 
@@ -6884,7 +7102,7 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size,
 
       if (duration < 0)
         return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvReferenceBlock) {
+    } else if (id == libwebm::kMkvReferenceBlock) {
       if (size > 8 || size <= 0)
         return E_FILE_FORMAT_INVALID;
       const long size_ = static_cast<long>(size);
@@ -7231,7 +7449,6 @@ const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
 
 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
 BlockEntry::~BlockEntry() {}
-bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
 long BlockEntry::GetIndex() const { return m_index; }
 
@@ -7555,7 +7772,6 @@ long Block::Parse(const Cluster* pCluster) {
       if (pf >= pf_end)
         return E_FILE_FORMAT_INVALID;
 
-
       const Frame& prev = *pf++;
       assert(prev.len == frame_size);
       if (prev.len != frame_size)
@@ -7581,7 +7797,7 @@ long Block::Parse(const Cluster* pCluster) {
       if (pos > stop)
         return E_FILE_FORMAT_INVALID;
 
-      const int exp = 7 * len - 1;
+      const long exp = 7 * len - 1;
       const long long bias = (1LL << exp) - 1LL;
       const long long delta_size = delta_size_ - bias;
 
@@ -7721,4 +7937,4 @@ long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
 
 long long Block::GetDiscardPadding() const { return m_discard_padding; }
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
similarity index 90%
rename from third_party/libwebm/mkvparser.hpp
rename to third_party/libwebm/mkvparser/mkvparser.h
index 75ef69d76d1a43d04246ecc0b1216df2af5e9493..42e6e88ab46b0af885f4ad87437029b4ca7bcfd1 100644 (file)
@@ -5,13 +5,10 @@
 // tree. An additional intellectual property rights grant can be found
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
-
-#ifndef MKVPARSER_HPP
-#define MKVPARSER_HPP
+#ifndef MKVPARSER_MKVPARSER_H_
+#define MKVPARSER_MKVPARSER_H_
 
 #include <cstddef>
-#include <cstdio>
-#include <cstdlib>
 
 namespace mkvparser {
 
@@ -28,8 +25,9 @@ class IMkvReader {
   virtual ~IMkvReader();
 };
 
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
-                                             unsigned long long element_size);
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+                     unsigned long long element_size);
 long long GetUIntLength(IMkvReader*, long long, long&);
 long long ReadUInt(IMkvReader*, long long, long&);
 long long ReadID(IMkvReader* pReader, long long pos, long& len);
@@ -128,7 +126,7 @@ class BlockEntry {
  public:
   virtual ~BlockEntry();
 
-  bool EOS() const;
+  bool EOS() const { return (GetKind() == kBlockEOS); }
   const Cluster* GetCluster() const;
   long GetIndex() const;
   virtual const Block* GetBlock() const = 0;
@@ -391,6 +389,90 @@ class Track {
   ContentEncoding** content_encoding_entries_end_;
 };
 
+struct PrimaryChromaticity {
+  PrimaryChromaticity() : x(0), y(0) {}
+  ~PrimaryChromaticity() {}
+  static bool Parse(IMkvReader* reader, long long read_pos,
+                    long long value_size, bool is_x,
+                    PrimaryChromaticity** chromaticity);
+  float x;
+  float y;
+};
+
+struct MasteringMetadata {
+  static const float kValueNotPresent;
+
+  MasteringMetadata()
+      : r(NULL),
+        g(NULL),
+        b(NULL),
+        white_point(NULL),
+        luminance_max(kValueNotPresent),
+        luminance_min(kValueNotPresent) {}
+  ~MasteringMetadata() {
+    delete r;
+    delete g;
+    delete b;
+    delete white_point;
+  }
+
+  static bool Parse(IMkvReader* reader, long long element_start,
+                    long long element_size,
+                    MasteringMetadata** mastering_metadata);
+
+  PrimaryChromaticity* r;
+  PrimaryChromaticity* g;
+  PrimaryChromaticity* b;
+  PrimaryChromaticity* white_point;
+  float luminance_max;
+  float luminance_min;
+};
+
+struct Colour {
+  static const long long kValueNotPresent;
+
+  // Unless otherwise noted all values assigned upon construction are the
+  // equivalent of unspecified/default.
+  Colour()
+      : matrix_coefficients(kValueNotPresent),
+        bits_per_channel(kValueNotPresent),
+        chroma_subsampling_horz(kValueNotPresent),
+        chroma_subsampling_vert(kValueNotPresent),
+        cb_subsampling_horz(kValueNotPresent),
+        cb_subsampling_vert(kValueNotPresent),
+        chroma_siting_horz(kValueNotPresent),
+        chroma_siting_vert(kValueNotPresent),
+        range(kValueNotPresent),
+        transfer_characteristics(kValueNotPresent),
+        primaries(kValueNotPresent),
+        max_cll(kValueNotPresent),
+        max_fall(kValueNotPresent),
+        mastering_metadata(NULL) {}
+  ~Colour() {
+    delete mastering_metadata;
+    mastering_metadata = NULL;
+  }
+
+  static bool Parse(IMkvReader* reader, long long element_start,
+                    long long element_size, Colour** colour);
+
+  long long matrix_coefficients;
+  long long bits_per_channel;
+  long long chroma_subsampling_horz;
+  long long chroma_subsampling_vert;
+  long long cb_subsampling_horz;
+  long long cb_subsampling_vert;
+  long long chroma_siting_horz;
+  long long chroma_siting_vert;
+  long long range;
+  long long transfer_characteristics;
+  long long primaries;
+  long long max_cll;
+  long long max_fall;
+
+  MasteringMetadata* mastering_metadata;
+};
+
 class VideoTrack : public Track {
   VideoTrack(const VideoTrack&);
   VideoTrack& operator=(const VideoTrack&);
@@ -398,6 +480,7 @@ class VideoTrack : public Track {
   VideoTrack(Segment*, long long element_start, long long element_size);
 
  public:
+  virtual ~VideoTrack();
   static long Parse(Segment*, const Info&, long long element_start,
                     long long element_size, VideoTrack*&);
 
@@ -412,6 +495,8 @@ class VideoTrack : public Track {
   bool VetEntry(const BlockEntry*) const;
   long Seek(long long time_ns, const BlockEntry*&) const;
 
+  Colour* GetColour() const;
+
  private:
   long long m_width;
   long long m_height;
@@ -421,6 +506,8 @@ class VideoTrack : public Track {
   long long m_stereo_mode;
 
   double m_rate;
+
+  Colour* m_colour;
 };
 
 class AudioTrack : public Track {
@@ -1013,7 +1100,7 @@ class Segment {
   const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
 };
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
 
 inline long mkvparser::Segment::LoadCluster() {
   long long pos;
@@ -1022,4 +1109,4 @@ inline long mkvparser::Segment::LoadCluster() {
   return LoadCluster(pos, size);
 }
 
-#endif  // MKVPARSER_HPP
+#endif  // MKVPARSER_MKVPARSER_H_
similarity index 97%
rename from third_party/libwebm/mkvreader.cpp
rename to third_party/libwebm/mkvparser/mkvreader.cc
index eaf9e0a799f2a5e67296ec352ddf9fd20a3777b4..9f90d8c4f869599009094e2abf82599432c5e77f 100644 (file)
@@ -5,8 +5,7 @@
 // tree. An additional intellectual property rights grant can be found
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
-
-#include "mkvreader.hpp"
+#include "mkvparser/mkvreader.h"
 
 #include <cassert>
 
@@ -129,4 +128,4 @@ int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
   return 0;  // success
 }
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
\ No newline at end of file
similarity index 87%
rename from third_party/libwebm/mkvreader.hpp
rename to third_party/libwebm/mkvparser/mkvreader.h
index 82ebad54444a1faf1769618091dafec004a93a8c..9831ecf6458615bf159ee5807b2eaa4295bf8651 100644 (file)
@@ -5,13 +5,13 @@
 // tree. An additional intellectual property rights grant can be found
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
+#ifndef MKVPARSER_MKVREADER_H_
+#define MKVPARSER_MKVREADER_H_
 
-#ifndef MKVREADER_HPP
-#define MKVREADER_HPP
-
-#include "mkvparser.hpp"
 #include <cstdio>
 
+#include "mkvparser/mkvparser.h"
+
 namespace mkvparser {
 
 class MkvReader : public IMkvReader {
@@ -40,6 +40,6 @@ class MkvReader : public IMkvReader {
   bool reader_owns_file_;
 };
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
 
-#endif  // MKVREADER_HPP
+#endif  // MKVPARSER_MKVREADER_H_
index c4539a0b947a99ab350eb1974fdc79c574a947a2..81150aa66b345fd22cc697aa862c3bbb911450a6 100644 (file)
@@ -13,8 +13,8 @@
 #include <cstring>
 #include <cstdio>
 
-#include "third_party/libwebm/mkvparser.hpp"
-#include "third_party/libwebm/mkvreader.hpp"
+#include "third_party/libwebm/mkvparser/mkvparser.h"
+#include "third_party/libwebm/mkvparser/mkvreader.h"
 
 namespace {
 
index d41e700443c6cf941f61fe9171687508257498c6..caf439157cb4ac85fc9e83a17ffdd42df98728e5 100644 (file)
@@ -11,9 +11,9 @@
 
 #include <string>
 
-#include "third_party/libwebm/mkvmuxer.hpp"
-#include "third_party/libwebm/mkvmuxerutil.hpp"
-#include "third_party/libwebm/mkvwriter.hpp"
+#include "third_party/libwebm/mkvmuxer/mkvmuxer.h"
+#include "third_party/libwebm/mkvmuxer/mkvmuxerutil.h"
+#include "third_party/libwebm/mkvmuxer/mkvwriter.h"
 
 namespace {
 const uint64_t kDebugTrackUid = 0xDEADBEEF;