Merge "Use an exponential growth approach for the ANS reversal buffer." into nextgenv2
diff --git a/build/make/configure.sh b/build/make/configure.sh
index d888268..b305d33 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -644,6 +644,9 @@
 
     # detect tgt_isa
     case "$gcctarget" in
+      aarch64*)
+        tgt_isa=arm64
+        ;;
       armv6*)
         tgt_isa=armv6
         ;;
@@ -1187,6 +1190,12 @@
               soft_disable avx2
               ;;
           esac
+          case $vc_version in
+            7|8|9)
+              echo "${tgt_cc} omits stdint.h, disabling webm-io..."
+              soft_disable webm_io
+              ;;
+          esac
           ;;
       esac
 
diff --git a/configure b/configure
index edb8a36..eedbf7f 100755
--- a/configure
+++ b/configure
@@ -103,6 +103,7 @@
 all_platforms="${all_platforms} armv6-linux-gcc"
 all_platforms="${all_platforms} armv6-none-rvct"
 all_platforms="${all_platforms} arm64-darwin-gcc"
+all_platforms="${all_platforms} arm64-linux-gcc"
 all_platforms="${all_platforms} armv7-android-gcc"   #neon Cortex-A8
 all_platforms="${all_platforms} armv7-darwin-gcc"    #neon Cortex-A8
 all_platforms="${all_platforms} armv7-linux-rvct"    #neon Cortex-A8
diff --git a/examples.mk b/examples.mk
index 13af086..593c8dd 100644
--- a/examples.mk
+++ b/examples.mk
@@ -36,21 +36,30 @@
                 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.cpp \
-                      third_party/libwebm/mkvreader.cpp \
-                      third_party/libwebm/mkvparser.hpp \
-                      third_party/libwebm/mkvreader.hpp
+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
+
 
 # List of examples to build. UTILS are tools meant for distribution
 # while EXAMPLES demonstrate specific portions of the API.
@@ -70,6 +79,7 @@
 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 @@
 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 e6fb068..c2a4725 100644
--- a/libs.mk
+++ b/libs.mk
@@ -394,6 +394,12 @@
 $(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 @@
             $(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)
diff --git a/test/active_map_test.cc b/test/active_map_test.cc
index 0221995..dc3de72 100644
--- a/test/active_map_test.cc
+++ b/test/active_map_test.cc
@@ -85,5 +85,5 @@
 
 VP9_INSTANTIATE_TEST_CASE(ActiveMapTest,
                           ::testing::Values(::libvpx_test::kRealTime),
-                          ::testing::Range(0, 6));
+                          ::testing::Range(0, 9));
 }  // namespace
diff --git a/test/dct16x16_test.cc b/test/dct16x16_test.cc
index d6cc5e4..c4dfaf3 100644
--- a/test/dct16x16_test.cc
+++ b/test/dct16x16_test.cc
@@ -792,6 +792,67 @@
   CompareInvReference(ref_txfm_, thresh_);
 }
 
+class PartialTrans16x16Test
+    : public ::testing::TestWithParam<
+          std::tr1::tuple<FdctFunc, vpx_bit_depth_t> > {
+ public:
+  virtual ~PartialTrans16x16Test() {}
+  virtual void SetUp() {
+    fwd_txfm_ = GET_PARAM(0);
+    bit_depth_ = GET_PARAM(1);
+  }
+
+  virtual void TearDown() { libvpx_test::ClearSystemState(); }
+
+ protected:
+  vpx_bit_depth_t bit_depth_;
+  FdctFunc fwd_txfm_;
+};
+
+TEST_P(PartialTrans16x16Test, Extremes) {
+#if CONFIG_VP9_HIGHBITDEPTH
+  const int16_t maxval =
+      static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+  const int16_t maxval = 255;
+#endif
+  const int minval = -maxval;
+  DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+  DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+
+  for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+  EXPECT_EQ((maxval * kNumCoeffs) >> 1, output[0]);
+
+  for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+  EXPECT_EQ((minval * kNumCoeffs) >> 1, output[0]);
+}
+
+TEST_P(PartialTrans16x16Test, Random) {
+#if CONFIG_VP9_HIGHBITDEPTH
+  const int16_t maxval =
+      static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+  const int16_t maxval = 255;
+#endif
+  DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+  DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+  ACMRandom rnd(ACMRandom::DeterministicSeed());
+
+  int sum = 0;
+  for (int i = 0; i < kNumCoeffs; ++i) {
+    const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
+    input[i] = val;
+    sum += val;
+  }
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 16));
+  EXPECT_EQ(sum >> 1, output[0]);
+}
+
 using std::tr1::make_tuple;
 
 #if CONFIG_VP9_HIGHBITDEPTH
@@ -824,6 +885,11 @@
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(
+    C, PartialTrans16x16Test,
+    ::testing::Values(make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_8),
+                      make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_10),
+                      make_tuple(&vpx_highbd_fdct16x16_1_c, VPX_BITS_12)));
 #else
 INSTANTIATE_TEST_CASE_P(
     C, Trans16x16HT,
@@ -832,6 +898,9 @@
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 1, VPX_BITS_8),
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 2, VPX_BITS_8),
         make_tuple(&vp9_fht16x16_c, &vp9_iht16x16_256_add_c, 3, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(C, PartialTrans16x16Test,
+                        ::testing::Values(make_tuple(&vpx_fdct16x16_1_c,
+                                                     VPX_BITS_8)));
 #endif  // CONFIG_VP9_HIGHBITDEPTH
 
 #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -859,6 +928,9 @@
                    VPX_BITS_8),
         make_tuple(&vp9_fht16x16_sse2, &vp9_iht16x16_256_add_sse2, 3,
                    VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
+                        ::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 
 #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -896,6 +968,9 @@
                    &idct16x16_10_add_12_sse2, 3167, VPX_BITS_12),
         make_tuple(&idct16x16_12,
                    &idct16x16_256_add_12_sse2, 3167, VPX_BITS_12)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans16x16Test,
+                        ::testing::Values(make_tuple(&vpx_fdct16x16_1_sse2,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 
 #if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -912,5 +987,8 @@
         make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 2, VPX_BITS_8),
         make_tuple(&vp9_fht16x16_msa, &vp9_iht16x16_256_add_msa, 3,
                    VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(MSA, PartialTrans16x16Test,
+                        ::testing::Values(make_tuple(&vpx_fdct16x16_1_msa,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 }  // namespace
diff --git a/test/dct32x32_test.cc b/test/dct32x32_test.cc
index 2dac10b..1cbac5c 100644
--- a/test/dct32x32_test.cc
+++ b/test/dct32x32_test.cc
@@ -305,6 +305,67 @@
   }
 }
 
+class PartialTrans32x32Test
+    : public ::testing::TestWithParam<
+          std::tr1::tuple<FwdTxfmFunc, vpx_bit_depth_t> > {
+ public:
+  virtual ~PartialTrans32x32Test() {}
+  virtual void SetUp() {
+    fwd_txfm_ = GET_PARAM(0);
+    bit_depth_ = GET_PARAM(1);
+  }
+
+  virtual void TearDown() { libvpx_test::ClearSystemState(); }
+
+ protected:
+  vpx_bit_depth_t bit_depth_;
+  FwdTxfmFunc fwd_txfm_;
+};
+
+TEST_P(PartialTrans32x32Test, Extremes) {
+#if CONFIG_VP9_HIGHBITDEPTH
+  const int16_t maxval =
+      static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+  const int16_t maxval = 255;
+#endif
+  const int minval = -maxval;
+  DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+  DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+
+  for (int i = 0; i < kNumCoeffs; ++i) input[i] = maxval;
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+  EXPECT_EQ((maxval * kNumCoeffs) >> 3, output[0]);
+
+  for (int i = 0; i < kNumCoeffs; ++i) input[i] = minval;
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+  EXPECT_EQ((minval * kNumCoeffs) >> 3, output[0]);
+}
+
+TEST_P(PartialTrans32x32Test, Random) {
+#if CONFIG_VP9_HIGHBITDEPTH
+  const int16_t maxval =
+      static_cast<int16_t>(clip_pixel_highbd(1 << 30, bit_depth_));
+#else
+  const int16_t maxval = 255;
+#endif
+  DECLARE_ALIGNED(16, int16_t, input[kNumCoeffs]);
+  DECLARE_ALIGNED(16, tran_low_t, output[kNumCoeffs]);
+  ACMRandom rnd(ACMRandom::DeterministicSeed());
+
+  int sum = 0;
+  for (int i = 0; i < kNumCoeffs; ++i) {
+    const int val = (i & 1) ? -rnd(maxval + 1) : rnd(maxval + 1);
+    input[i] = val;
+    sum += val;
+  }
+  output[0] = 0;
+  ASM_REGISTER_STATE_CHECK(fwd_txfm_(input, output, 32));
+  EXPECT_EQ(sum >> 3, output[0]);
+}
+
 using std::tr1::make_tuple;
 
 #if CONFIG_VP9_HIGHBITDEPTH
@@ -323,6 +384,11 @@
                    &vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_c,
                    &vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(
+    C, PartialTrans32x32Test,
+    ::testing::Values(make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_8),
+                      make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_10),
+                      make_tuple(&vpx_highbd_fdct32x32_1_c, VPX_BITS_12)));
 #else
 INSTANTIATE_TEST_CASE_P(
     C, Trans32x32Test,
@@ -331,9 +397,12 @@
                    &vpx_idct32x32_1024_add_c, 0, VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_c,
                    &vpx_idct32x32_1024_add_c, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(C, PartialTrans32x32Test,
+                        ::testing::Values(make_tuple(&vpx_fdct32x32_1_c,
+                                                     VPX_BITS_8)));
 #endif  // CONFIG_VP9_HIGHBITDEPTH
 
-#if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
+#if HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 INSTANTIATE_TEST_CASE_P(
     NEON, Trans32x32Test,
     ::testing::Values(
@@ -341,7 +410,7 @@
                    &vpx_idct32x32_1024_add_neon, 0, VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_c,
                    &vpx_idct32x32_1024_add_neon, 1, VPX_BITS_8)));
-#endif  // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
+#endif  // HAVE_NEON && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 
 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 INSTANTIATE_TEST_CASE_P(
@@ -351,6 +420,9 @@
                    &vpx_idct32x32_1024_add_sse2, 0, VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_sse2,
                    &vpx_idct32x32_1024_add_sse2, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test,
+                        ::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 
 #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -367,6 +439,9 @@
                    VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_sse2, &vpx_idct32x32_1024_add_c, 1,
                    VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(SSE2, PartialTrans32x32Test,
+                        ::testing::Values(make_tuple(&vpx_fdct32x32_1_sse2,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 
 #if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
@@ -387,5 +462,8 @@
                    &vpx_idct32x32_1024_add_msa, 0, VPX_BITS_8),
         make_tuple(&vpx_fdct32x32_rd_msa,
                    &vpx_idct32x32_1024_add_msa, 1, VPX_BITS_8)));
+INSTANTIATE_TEST_CASE_P(MSA, PartialTrans32x32Test,
+                        ::testing::Values(make_tuple(&vpx_fdct32x32_1_msa,
+                                                     VPX_BITS_8)));
 #endif  // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE
 }  // namespace
diff --git a/test/superframe_test.cc b/test/superframe_test.cc
index 4fc9555..e6852e3 100644
--- a/test/superframe_test.cc
+++ b/test/superframe_test.cc
@@ -108,7 +108,11 @@
     ::testing::Values(::libvpx_test::kTwoPassGood),
     ::testing::Values(0)));
 
+// The superframe index is currently mandatory with ANS due to the decoder
+// starting at the end of the buffer.
+#if !CONFIG_ANS
 VP10_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Combine(
     ::testing::Values(::libvpx_test::kTwoPassGood),
     ::testing::Values(1)));
+#endif
 }  // namespace
diff --git a/test/test.mk b/test/test.mk
index 7c3f101..59f054c 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -60,10 +60,10 @@
 
 ## 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
diff --git a/test/vp10_fht4x4_test.cc b/test/vp10_fht4x4_test.cc
index 2e9d2d4..63d9ec7 100644
--- a/test/vp10_fht4x4_test.cc
+++ b/test/vp10_fht4x4_test.cc
@@ -119,10 +119,12 @@
 }
 #endif  // CONFIG_VP9_HIGHBITDEPTH
 
+#define SPEED_TEST (0)
+#if SPEED_TEST
 #if CONFIG_EXT_TX
 TEST(VP10Trans4x4HTSpeedTest, C_version) {
     ACMRandom rnd(ACMRandom::DeterministicSeed());
-    const int count_test_block = 20000;
+    const int count_test_block = 200000;
     int bit_depth = 8;
     int mask = (1 << bit_depth) - 1;
     const int num_coeffs = 16;
@@ -131,10 +133,10 @@
     const int stride = 4;
     int tx_type;
 
+    for (int j = 0; j < num_coeffs; ++j) {
+      input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
+    }
     for (int i = 0; i < count_test_block; ++i) {
-      for (int j = 0; j < num_coeffs; ++j) {
-        input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
-      }
       for (tx_type = V_DCT; tx_type <= H_FLIPADST; ++tx_type) {
         vp10_fht4x4_c(input, output, stride, tx_type);
       }
@@ -148,28 +150,30 @@
 #if HAVE_SSE2 && CONFIG_EXT_TX
 TEST(VP10Trans4x4HTSpeedTest, SSE2_version) {
     ACMRandom rnd(ACMRandom::DeterministicSeed());
-    const int count_test_block = 20000;
+    const int count_test_block = 200000;
     int bit_depth = 8;
     int mask = (1 << bit_depth) - 1;
     const int num_coeffs = 16;
     int16_t *input = new int16_t[num_coeffs];
-    tran_low_t *output = new tran_low_t[num_coeffs];
+    tran_low_t *output = reinterpret_cast<tran_low_t *>(
+        vpx_memalign(16, num_coeffs * sizeof(tran_low_t)));
     const int stride = 4;
     int tx_type;
 
+    for (int j = 0; j < num_coeffs; ++j) {
+      input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
+    }
     for (int i = 0; i < count_test_block; ++i) {
-      for (int j = 0; j < num_coeffs; ++j) {
-        input[j] = (rnd.Rand8() & mask) - (rnd.Rand8() & mask);
-      }
       for (tx_type = V_DCT; tx_type <= H_FLIPADST; ++tx_type) {
         vp10_fht4x4_sse2(input, output, stride, tx_type);
       }
     }
 
     delete[] input;
-    delete[] output;
+    vpx_free(output);
 }
 #endif  // HAVE_SSE2 && CONFIG_EXT_TX
+#endif  // SPEED_TEST
 
 using std::tr1::make_tuple;
 
@@ -225,16 +229,16 @@
     SSE4_1, VP10HighbdTrans4x4HT,
     ::testing::Values(
 #if !CONFIG_EXT_TX
-      make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
-                 VPX_BITS_10, 16),
+      // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+      //            VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
                  VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
                  VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 3,
                  VPX_BITS_10, 16),
-      make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
-                 VPX_BITS_12, 16),
+      // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+      //            VPX_BITS_12, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
                  VPX_BITS_12, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
@@ -242,8 +246,8 @@
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 3,
                  VPX_BITS_12, 16)));
 #else
-      make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
-                 VPX_BITS_10, 16),
+      // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+      //            VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
                  VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
@@ -272,8 +276,8 @@
                  VPX_BITS_10, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 15,
                  VPX_BITS_10, 16),
-      make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
-                 VPX_BITS_12, 16),
+      // make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 0,
+      //            VPX_BITS_12, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 1,
                  VPX_BITS_12, 16),
       make_tuple(&vp10_highbd_fht4x4_sse4_1, &vp10_highbd_iht4x4_16_add_c, 2,
diff --git a/third_party/libwebm/Android.mk b/third_party/libwebm/Android.mk
index be9d77d..8149a08 100644
--- a/third_party/libwebm/Android.mk
+++ b/third_party/libwebm/Android.mk
@@ -2,9 +2,16 @@
 
 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)
diff --git a/third_party/libwebm/README.libvpx b/third_party/libwebm/README.libvpx
index 2989d3d..73f8303 100644
--- a/third_party/libwebm/README.libvpx
+++ b/third_party/libwebm/README.libvpx
@@ -1,5 +1,5 @@
 URL: https://chromium.googlesource.com/webm/libwebm
-Version: 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
index a7e9f03..0000000
--- a/third_party/libwebm/RELEASE.TXT
+++ /dev/null
@@ -1,34 +0,0 @@
-1.0.0.5

- * Handled case when no duration

- * Handled empty clusters

- * Handled empty clusters when seeking

- * Implemented check lacing bits

-

-1.0.0.4

- * Made Cues member variables mutables

- * Defined against badly-formatted cue points

- * Segment::GetCluster returns CuePoint too

- * Separated cue-based searches

-

-1.0.0.3

- * Added Block::GetOffset() to get a frame's offset in a block

- * Changed cluster count type from size_t to long

- * Parsed SeekHead to find cues

- * Allowed seeking beyond end of cluster cache

- * Added not to attempt to reparse cues element

- * Restructured Segment::LoadCluster

- * Marked position of cues without parsing cues element

- * Allowed cue points to be loaded incrementally

- * Implemented to load lazily cue points as they're searched

- * Merged Cues::LoadCuePoint into Cues::Find

- * Lazy init cues

- * Loaded cue point during find

-

-1.0.0.2

- * added support for Cues element

- * seeking was improved

-

-1.0.0.1

- * fixed item 141

- * added item 142

- * added this file, RELEASE.TXT, to repository

diff --git a/third_party/libwebm/common/file_util.cc b/third_party/libwebm/common/file_util.cc
new file mode 100644
index 0000000..4f91318
--- /dev/null
+++ b/third_party/libwebm/common/file_util.cc
@@ -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
index 0000000..0e71eac
--- /dev/null
+++ b/third_party/libwebm/common/file_util.h
@@ -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
index 0000000..e1a9842
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.cc
@@ -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
index 0000000..d30c2b9
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.h
@@ -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_
diff --git a/third_party/libwebm/webmids.hpp b/third_party/libwebm/common/webmids.h
similarity index 79%
rename from third_party/libwebm/webmids.hpp
rename to third_party/libwebm/common/webmids.h
index ad4ab57..32a0c5f 100644
--- a/third_party/libwebm/webmids.hpp
+++ b/third_party/libwebm/common/webmids.h
@@ -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 @@
   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 @@
   kMkvTagString = 0x4487
 };
 
-}  // end namespace mkvmuxer
+}  // namespace libwebm
 
-#endif  // WEBMIDS_HPP
+#endif  // COMMON_WEBMIDS_H_
diff --git a/third_party/libwebm/mkvmuxer.cpp b/third_party/libwebm/mkvmuxer.cpp
deleted file mode 100644
index 9be3119..0000000
--- a/third_party/libwebm/mkvmuxer.cpp
+++ /dev/null
@@ -1,3277 +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.
-
-#include "mkvmuxer.hpp"
-
-#include <climits>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-#include <new>
-
-#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
-
-namespace mkvmuxer {
-
-namespace {
-// Deallocate the string designated by |dst|, and then copy the |src|
-// string to |dst|.  The caller owns both the |src| string and the
-// |dst| copy (hence the caller is responsible for eventually
-// deallocating the strings, either directly, or indirectly via
-// StrCpy).  Returns true if the source string was successfully copied
-// to the destination.
-bool StrCpy(const char* src, char** dst_ptr) {
-  if (dst_ptr == NULL)
-    return false;
-
-  char*& dst = *dst_ptr;
-
-  delete[] dst;
-  dst = NULL;
-
-  if (src == NULL)
-    return true;
-
-  const size_t size = strlen(src) + 1;
-
-  dst = new (std::nothrow) char[size];  // NOLINT
-  if (dst == NULL)
-    return false;
-
-  strcpy(dst, src);  // NOLINT
-  return true;
-}
-}  // namespace
-
-///////////////////////////////////////////////////////////////
-//
-// IMkvWriter Class
-
-IMkvWriter::IMkvWriter() {}
-
-IMkvWriter::~IMkvWriter() {}
-
-bool WriteEbmlHeader(IMkvWriter* writer, uint64 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);
-
-  if (!WriteEbmlMasterElement(writer, kMkvEBML, size))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLVersion, 1ULL))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLReadVersion, 1ULL))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLMaxIDLength, 4ULL))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvEBMLMaxSizeLength, 8ULL))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvDocType, "webm"))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvDocTypeVersion, doc_type_version))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvDocTypeReadVersion, 2ULL))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlHeader(IMkvWriter* writer) {
-  return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
-}
-
-bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
-                 mkvmuxer::int64 start, int64 size) {
-  // TODO(vigneshv): Check if this is a reasonable value.
-  const uint32 kBufSize = 2048;
-  uint8* buf = new uint8[kBufSize];
-  int64 offset = start;
-  while (size > 0) {
-    const int64 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));
-    offset += read_len;
-    size -= read_len;
-  }
-  delete[] buf;
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Frame Class
-
-Frame::Frame()
-    : add_id_(0),
-      additional_(NULL),
-      additional_length_(0),
-      duration_(0),
-      frame_(NULL),
-      is_key_(false),
-      length_(0),
-      track_number_(0),
-      timestamp_(0),
-      discard_padding_(0),
-      reference_block_timestamp_(0),
-      reference_block_timestamp_set_(false) {}
-
-Frame::~Frame() {
-  delete[] frame_;
-  delete[] additional_;
-}
-
-bool Frame::CopyFrom(const Frame& frame) {
-  delete[] frame_;
-  frame_ = NULL;
-  length_ = 0;
-  if (frame.length() > 0 && frame.frame() != NULL &&
-      !Init(frame.frame(), frame.length())) {
-    return false;
-  }
-  add_id_ = 0;
-  delete[] additional_;
-  additional_ = NULL;
-  additional_length_ = 0;
-  if (frame.additional_length() > 0 && frame.additional() != NULL &&
-      !AddAdditionalData(frame.additional(), frame.additional_length(),
-                         frame.add_id())) {
-    return false;
-  }
-  duration_ = frame.duration();
-  is_key_ = frame.is_key();
-  track_number_ = frame.track_number();
-  timestamp_ = frame.timestamp();
-  discard_padding_ = frame.discard_padding();
-  return true;
-}
-
-bool Frame::Init(const uint8* frame, uint64 length) {
-  uint8* const data =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
-  if (!data)
-    return false;
-
-  delete[] frame_;
-  frame_ = data;
-  length_ = length;
-
-  memcpy(frame_, frame, static_cast<size_t>(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
-  if (!data)
-    return false;
-
-  delete[] additional_;
-  additional_ = data;
-  additional_length_ = length;
-  add_id_ = add_id;
-
-  memcpy(additional_, additional, static_cast<size_t>(additional_length_));
-  return true;
-}
-
-bool Frame::IsValid() const {
-  if (length_ == 0 || !frame_) {
-    return false;
-  }
-  if ((additional_length_ != 0 && !additional_) ||
-      (additional_ != NULL && additional_length_ == 0)) {
-    return false;
-  }
-  if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
-    return false;
-  }
-  if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
-    return false;
-  }
-  return true;
-}
-
-bool Frame::CanBeSimpleBlock() const {
-  return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
-}
-
-void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
-  reference_block_timestamp_ = reference_block_timestamp;
-  reference_block_timestamp_set_ = true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// CuePoint Class
-
-CuePoint::CuePoint()
-    : time_(0),
-      track_(0),
-      cluster_pos_(0),
-      block_number_(1),
-      output_block_number_(true) {}
-
-CuePoint::~CuePoint() {}
-
-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_);
-  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;
-
-  if (!WriteEbmlMasterElement(writer, kMkvCuePoint, payload_size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvCueTime, time_))
-    return false;
-
-  if (!WriteEbmlMasterElement(writer, kMkvCueTrackPositions, size))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvCueTrack, track_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvCueClusterPosition, cluster_pos_))
-    return false;
-  if (output_block_number_ && block_number_ > 1)
-    if (!WriteEbmlElement(writer, kMkvCueBlockNumber, block_number_))
-      return false;
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0)
-    return false;
-
-  if (stop_position - payload_position != static_cast<int64>(payload_size))
-    return false;
-
-  return true;
-}
-
-uint64 CuePoint::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvCueClusterPosition, cluster_pos_);
-  size += EbmlElementSize(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;
-
-  return payload_size;
-}
-
-uint64 CuePoint::Size() const {
-  const uint64 payload_size = PayloadSize();
-  return EbmlMasterElementSize(kMkvCuePoint, payload_size) + payload_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Cues Class
-
-Cues::Cues()
-    : cue_entries_capacity_(0),
-      cue_entries_size_(0),
-      cue_entries_(NULL),
-      output_block_number_(true) {}
-
-Cues::~Cues() {
-  if (cue_entries_) {
-    for (int32 i = 0; i < cue_entries_size_; ++i) {
-      CuePoint* const cue = cue_entries_[i];
-      delete cue;
-    }
-    delete[] cue_entries_;
-  }
-}
-
-bool Cues::AddCue(CuePoint* cue) {
-  if (!cue)
-    return false;
-
-  if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
-    // Add more CuePoints.
-    const int32 new_capacity =
-        (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
-
-    if (new_capacity < 1)
-      return false;
-
-    CuePoint** const cues =
-        new (std::nothrow) CuePoint*[new_capacity];  // NOLINT
-    if (!cues)
-      return false;
-
-    for (int32 i = 0; i < cue_entries_size_; ++i) {
-      cues[i] = cue_entries_[i];
-    }
-
-    delete[] cue_entries_;
-
-    cue_entries_ = cues;
-    cue_entries_capacity_ = new_capacity;
-  }
-
-  cue->set_output_block_number(output_block_number_);
-  cue_entries_[cue_entries_size_++] = cue;
-  return true;
-}
-
-CuePoint* Cues::GetCueByIndex(int32 index) const {
-  if (cue_entries_ == NULL)
-    return NULL;
-
-  if (index >= cue_entries_size_)
-    return NULL;
-
-  return cue_entries_[index];
-}
-
-uint64 Cues::Size() {
-  uint64 size = 0;
-  for (int32 i = 0; i < cue_entries_size_; ++i)
-    size += GetCueByIndex(i)->Size();
-  size += EbmlMasterElementSize(kMkvCues, size);
-  return size;
-}
-
-bool Cues::Write(IMkvWriter* writer) const {
-  if (!writer)
-    return false;
-
-  uint64 size = 0;
-  for (int32 i = 0; i < cue_entries_size_; ++i) {
-    const CuePoint* const cue = GetCueByIndex(i);
-
-    if (!cue)
-      return false;
-
-    size += cue->Size();
-  }
-
-  if (!WriteEbmlMasterElement(writer, kMkvCues, size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  for (int32 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();
-  if (stop_position < 0)
-    return false;
-
-  if (stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// ContentEncAESSettings Class
-
-ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
-
-uint64 ContentEncAESSettings::Size() const {
-  const uint64 payload = PayloadSize();
-  const uint64 size =
-      EbmlMasterElementSize(kMkvContentEncAESSettings, payload) + payload;
-  return size;
-}
-
-bool ContentEncAESSettings::Write(IMkvWriter* writer) const {
-  const uint64 payload = PayloadSize();
-
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncAESSettings, payload))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvAESSettingsCipherMode, cipher_mode_))
-    return false;
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(payload))
-    return false;
-
-  return true;
-}
-
-uint64 ContentEncAESSettings::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvAESSettingsCipherMode, cipher_mode_);
-  return size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// ContentEncoding Class
-
-ContentEncoding::ContentEncoding()
-    : enc_algo_(5),
-      enc_key_id_(NULL),
-      encoding_order_(0),
-      encoding_scope_(1),
-      encoding_type_(1),
-      enc_key_id_length_(0) {}
-
-ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
-
-bool ContentEncoding::SetEncryptionID(const uint8* id, uint64 length) {
-  if (!id || length < 1)
-    return false;
-
-  delete[] enc_key_id_;
-
-  enc_key_id_ =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
-  if (!enc_key_id_)
-    return false;
-
-  memcpy(enc_key_id_, id, static_cast<size_t>(length));
-  enc_key_id_length_ = 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;
-
-  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 int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncoding, encoding_size))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingOrder, encoding_order_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingScope, encoding_scope_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncodingType, encoding_type_))
-    return false;
-
-  if (!WriteEbmlMasterElement(writer, kMkvContentEncryption, encryption_size))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncAlgo, enc_algo_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvContentEncKeyID, enc_key_id_,
-                        enc_key_id_length_))
-    return false;
-
-  if (!enc_aes_settings_.Write(writer))
-    return false;
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  return true;
-}
-
-uint64 ContentEncoding::EncodingSize(uint64 compresion_size,
-                                     uint64 encryption_size) const {
-  // TODO(fgalligan): Add support for compression settings.
-  if (compresion_size != 0)
-    return 0;
-
-  uint64 encoding_size = 0;
-
-  if (encryption_size > 0) {
-    encoding_size +=
-        EbmlMasterElementSize(kMkvContentEncryption, encryption_size) +
-        encryption_size;
-  }
-  encoding_size += EbmlElementSize(kMkvContentEncodingType, encoding_type_);
-  encoding_size += EbmlElementSize(kMkvContentEncodingScope, encoding_scope_);
-  encoding_size += EbmlElementSize(kMkvContentEncodingOrder, encoding_order_);
-
-  return encoding_size;
-}
-
-uint64 ContentEncoding::EncryptionSize() const {
-  const uint64 aes_size = enc_aes_settings_.Size();
-
-  uint64 encryption_size =
-      EbmlElementSize(kMkvContentEncKeyID, enc_key_id_, enc_key_id_length_);
-  encryption_size += EbmlElementSize(kMkvContentEncAlgo, enc_algo_);
-
-  return encryption_size + aes_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Track Class
-
-Track::Track(unsigned int* seed)
-    : codec_id_(NULL),
-      codec_private_(NULL),
-      language_(NULL),
-      max_block_additional_id_(0),
-      name_(NULL),
-      number_(0),
-      type_(0),
-      uid_(MakeUID(seed)),
-      codec_delay_(0),
-      seek_pre_roll_(0),
-      default_duration_(0),
-      codec_private_length_(0),
-      content_encoding_entries_(NULL),
-      content_encoding_entries_size_(0) {}
-
-Track::~Track() {
-  delete[] codec_id_;
-  delete[] codec_private_;
-  delete[] language_;
-  delete[] name_;
-
-  if (content_encoding_entries_) {
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
-      ContentEncoding* const encoding = content_encoding_entries_[i];
-      delete encoding;
-    }
-    delete[] content_encoding_entries_;
-  }
-}
-
-bool Track::AddContentEncoding() {
-  const uint32 count = content_encoding_entries_size_ + 1;
-
-  ContentEncoding** const content_encoding_entries =
-      new (std::nothrow) ContentEncoding*[count];  // NOLINT
-  if (!content_encoding_entries)
-    return false;
-
-  ContentEncoding* const content_encoding =
-      new (std::nothrow) ContentEncoding();  // NOLINT
-  if (!content_encoding) {
-    delete[] content_encoding_entries;
-    return false;
-  }
-
-  for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
-    content_encoding_entries[i] = content_encoding_entries_[i];
-  }
-
-  delete[] content_encoding_entries_;
-
-  content_encoding_entries_ = content_encoding_entries;
-  content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
-  content_encoding_entries_size_ = count;
-  return true;
-}
-
-ContentEncoding* Track::GetContentEncodingByIndex(uint32 index) const {
-  if (content_encoding_entries_ == NULL)
-    return NULL;
-
-  if (index >= content_encoding_entries_size_)
-    return NULL;
-
-  return content_encoding_entries_[index];
-}
-
-uint64 Track::PayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
-  size += EbmlElementSize(kMkvTrackUID, uid_);
-  size += EbmlElementSize(kMkvTrackType, type_);
-  if (codec_id_)
-    size += EbmlElementSize(kMkvCodecID, codec_id_);
-  if (codec_private_)
-    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
-                            codec_private_length_);
-  if (language_)
-    size += EbmlElementSize(kMkvLanguage, language_);
-  if (name_)
-    size += EbmlElementSize(kMkvName, name_);
-  if (max_block_additional_id_)
-    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
-  if (codec_delay_)
-    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
-  if (seek_pre_roll_)
-    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
-  if (default_duration_)
-    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
-
-  if (content_encoding_entries_size_ > 0) {
-    uint64 content_encodings_size = 0;
-    for (uint32 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;
-  }
-
-  return size;
-}
-
-uint64 Track::Size() const {
-  uint64 size = PayloadSize();
-  size += EbmlMasterElementSize(kMkvTrackEntry, size);
-  return size;
-}
-
-bool Track::Write(IMkvWriter* writer) const {
-  if (!writer)
-    return false;
-
-  // mandatory elements without a default value.
-  if (!type_ || !codec_id_)
-    return false;
-
-  // |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();
-
-  if (!WriteEbmlMasterElement(writer, kMkvTrackEntry, payload_size))
-    return false;
-
-  uint64 size = EbmlElementSize(kMkvTrackNumber, number_);
-  size += EbmlElementSize(kMkvTrackUID, uid_);
-  size += EbmlElementSize(kMkvTrackType, type_);
-  if (codec_id_)
-    size += EbmlElementSize(kMkvCodecID, codec_id_);
-  if (codec_private_)
-    size += EbmlElementSize(kMkvCodecPrivate, codec_private_,
-                            codec_private_length_);
-  if (language_)
-    size += EbmlElementSize(kMkvLanguage, language_);
-  if (name_)
-    size += EbmlElementSize(kMkvName, name_);
-  if (max_block_additional_id_)
-    size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
-  if (codec_delay_)
-    size += EbmlElementSize(kMkvCodecDelay, codec_delay_);
-  if (seek_pre_roll_)
-    size += EbmlElementSize(kMkvSeekPreRoll, seek_pre_roll_);
-  if (default_duration_)
-    size += EbmlElementSize(kMkvDefaultDuration, default_duration_);
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvTrackNumber, number_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvTrackUID, uid_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvTrackType, type_))
-    return false;
-  if (max_block_additional_id_) {
-    if (!WriteEbmlElement(writer, kMkvMaxBlockAdditionID,
-                          max_block_additional_id_)) {
-      return false;
-    }
-  }
-  if (codec_delay_) {
-    if (!WriteEbmlElement(writer, kMkvCodecDelay, codec_delay_))
-      return false;
-  }
-  if (seek_pre_roll_) {
-    if (!WriteEbmlElement(writer, kMkvSeekPreRoll, seek_pre_roll_))
-      return false;
-  }
-  if (default_duration_) {
-    if (!WriteEbmlElement(writer, kMkvDefaultDuration, default_duration_))
-      return false;
-  }
-  if (codec_id_) {
-    if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
-      return false;
-  }
-  if (codec_private_) {
-    if (!WriteEbmlElement(writer, kMkvCodecPrivate, codec_private_,
-                          codec_private_length_))
-      return false;
-  }
-  if (language_) {
-    if (!WriteEbmlElement(writer, kMkvLanguage, language_))
-      return false;
-  }
-  if (name_) {
-    if (!WriteEbmlElement(writer, kMkvName, name_))
-      return false;
-  }
-
-  int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  if (content_encoding_entries_size_ > 0) {
-    uint64 content_encodings_size = 0;
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
-      ContentEncoding* const encoding = content_encoding_entries_[i];
-      content_encodings_size += encoding->Size();
-    }
-
-    if (!WriteEbmlMasterElement(writer, kMkvContentEncodings,
-                                content_encodings_size))
-      return false;
-
-    for (uint32 i = 0; i < content_encoding_entries_size_; ++i) {
-      ContentEncoding* const encoding = content_encoding_entries_[i];
-      if (!encoding->Write(writer))
-        return false;
-    }
-  }
-
-  stop_position = writer->Position();
-  if (stop_position < 0)
-    return false;
-  return true;
-}
-
-bool Track::SetCodecPrivate(const uint8* codec_private, uint64 length) {
-  if (!codec_private || length < 1)
-    return false;
-
-  delete[] codec_private_;
-
-  codec_private_ =
-      new (std::nothrow) uint8[static_cast<size_t>(length)];  // NOLINT
-  if (!codec_private_)
-    return false;
-
-  memcpy(codec_private_, codec_private, static_cast<size_t>(length));
-  codec_private_length_ = length;
-
-  return true;
-}
-
-void Track::set_codec_id(const char* codec_id) {
-  if (codec_id) {
-    delete[] codec_id_;
-
-    const size_t length = strlen(codec_id) + 1;
-    codec_id_ = new (std::nothrow) char[length];  // NOLINT
-    if (codec_id_) {
-#ifdef _MSC_VER
-      strcpy_s(codec_id_, length, codec_id);
-#else
-      strcpy(codec_id_, codec_id);
-#endif
-    }
-  }
-}
-
-// TODO(fgalligan): Vet the language parameter.
-void Track::set_language(const char* language) {
-  if (language) {
-    delete[] language_;
-
-    const size_t length = strlen(language) + 1;
-    language_ = new (std::nothrow) char[length];  // NOLINT
-    if (language_) {
-#ifdef _MSC_VER
-      strcpy_s(language_, length, language);
-#else
-      strcpy(language_, language);
-#endif
-    }
-  }
-}
-
-void Track::set_name(const char* name) {
-  if (name) {
-    delete[] name_;
-
-    const size_t length = strlen(name) + 1;
-    name_ = new (std::nothrow) char[length];  // NOLINT
-    if (name_) {
-#ifdef _MSC_VER
-      strcpy_s(name_, length, name);
-#else
-      strcpy(name_, name);
-#endif
-    }
-  }
-}
-
-///////////////////////////////////////////////////////////////
-//
-// VideoTrack Class
-
-VideoTrack::VideoTrack(unsigned int* seed)
-    : Track(seed),
-      display_height_(0),
-      display_width_(0),
-      crop_left_(0),
-      crop_right_(0),
-      crop_top_(0),
-      crop_bottom_(0),
-      frame_rate_(0.0),
-      height_(0),
-      stereo_mode_(0),
-      alpha_mode_(0),
-      width_(0) {}
-
-VideoTrack::~VideoTrack() {}
-
-bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
-  if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
-      stereo_mode != kTopBottomRightIsFirst &&
-      stereo_mode != kTopBottomLeftIsFirst &&
-      stereo_mode != kSideBySideRightIsFirst)
-    return false;
-
-  stereo_mode_ = stereo_mode;
-  return true;
-}
-
-bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
-  if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
-    return false;
-
-  alpha_mode_ = alpha_mode;
-  return true;
-}
-
-uint64 VideoTrack::PayloadSize() const {
-  const uint64 parent_size = Track::PayloadSize();
-
-  uint64 size = VideoPayloadSize();
-  size += EbmlMasterElementSize(kMkvVideo, size);
-
-  return parent_size + size;
-}
-
-bool VideoTrack::Write(IMkvWriter* writer) const {
-  if (!Track::Write(writer))
-    return false;
-
-  const uint64 size = VideoPayloadSize();
-
-  if (!WriteEbmlMasterElement(writer, kMkvVideo, size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvPixelWidth, width_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvPixelHeight, height_))
-    return false;
-  if (display_width_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvDisplayWidth, display_width_))
-      return false;
-  }
-  if (display_height_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvDisplayHeight, display_height_))
-      return false;
-  }
-  if (crop_left_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropLeft, crop_left_))
-      return false;
-  }
-  if (crop_right_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropRight, crop_right_))
-      return false;
-  }
-  if (crop_top_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropTop, crop_top_))
-      return false;
-  }
-  if (crop_bottom_ > 0) {
-    if (!WriteEbmlElement(writer, kMkvPixelCropBottom, crop_bottom_))
-      return false;
-  }
-  if (stereo_mode_ > kMono) {
-    if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
-      return false;
-  }
-  if (alpha_mode_ > kNoAlpha) {
-    if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
-      return false;
-  }
-  if (frame_rate_ > 0.0) {
-    if (!WriteEbmlElement(writer, kMkvFrameRate,
-                          static_cast<float>(frame_rate_))) {
-      return false;
-    }
-  }
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size)) {
-    return false;
-  }
-
-  return true;
-}
-
-uint64 VideoTrack::VideoPayloadSize() const {
-  uint64 size = EbmlElementSize(kMkvPixelWidth, width_);
-  size += EbmlElementSize(kMkvPixelHeight, height_);
-  if (display_width_ > 0)
-    size += EbmlElementSize(kMkvDisplayWidth, display_width_);
-  if (display_height_ > 0)
-    size += EbmlElementSize(kMkvDisplayHeight, display_height_);
-  if (crop_left_ > 0)
-    size += EbmlElementSize(kMkvPixelCropLeft, crop_left_);
-  if (crop_right_ > 0)
-    size += EbmlElementSize(kMkvPixelCropRight, crop_right_);
-  if (crop_top_ > 0)
-    size += EbmlElementSize(kMkvPixelCropTop, crop_top_);
-  if (crop_bottom_ > 0)
-    size += EbmlElementSize(kMkvPixelCropBottom, crop_bottom_);
-  if (stereo_mode_ > kMono)
-    size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
-  if (alpha_mode_ > kNoAlpha)
-    size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
-  if (frame_rate_ > 0.0)
-    size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
-
-  return size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// AudioTrack Class
-
-AudioTrack::AudioTrack(unsigned int* seed)
-    : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
-
-AudioTrack::~AudioTrack() {}
-
-uint64 AudioTrack::PayloadSize() const {
-  const uint64 parent_size = Track::PayloadSize();
-
-  uint64 size =
-      EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
-  size += EbmlElementSize(kMkvChannels, channels_);
-  if (bit_depth_ > 0)
-    size += EbmlElementSize(kMkvBitDepth, bit_depth_);
-  size += EbmlMasterElementSize(kMkvAudio, size);
-
-  return parent_size + size;
-}
-
-bool AudioTrack::Write(IMkvWriter* writer) const {
-  if (!Track::Write(writer))
-    return false;
-
-  // Calculate AudioSettings size.
-  uint64 size =
-      EbmlElementSize(kMkvSamplingFrequency, static_cast<float>(sample_rate_));
-  size += EbmlElementSize(kMkvChannels, channels_);
-  if (bit_depth_ > 0)
-    size += EbmlElementSize(kMkvBitDepth, bit_depth_);
-
-  if (!WriteEbmlMasterElement(writer, kMkvAudio, size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvSamplingFrequency,
-                        static_cast<float>(sample_rate_)))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvChannels, channels_))
-    return false;
-  if (bit_depth_ > 0)
-    if (!WriteEbmlElement(writer, kMkvBitDepth, bit_depth_))
-      return false;
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Tracks Class
-
-const char Tracks::kOpusCodecId[] = "A_OPUS";
-const char Tracks::kVorbisCodecId[] = "A_VORBIS";
-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() {
-  if (track_entries_) {
-    for (uint32 i = 0; i < track_entries_size_; ++i) {
-      Track* const track = track_entries_[i];
-      delete track;
-    }
-    delete[] track_entries_;
-  }
-}
-
-bool Tracks::AddTrack(Track* track, int32 number) {
-  if (number < 0)
-    return false;
-
-  // This muxer only supports track numbers in the range [1, 126], in
-  // order to be able (to use Matroska integer representation) to
-  // serialize the block header (of which the track number is a part)
-  // for a frame using exactly 4 bytes.
-
-  if (number > 0x7E)
-    return false;
-
-  uint32 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) {
-      if (track_entries_[i]->number() == track_num)
-        return false;
-    }
-  }
-
-  const uint32 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) {
-    track_entries[i] = track_entries_[i];
-  }
-
-  delete[] track_entries_;
-
-  // Find the lowest availible track number > 0.
-  if (track_num == 0) {
-    track_num = count;
-
-    // Check to make sure a track does not already have |track_num|.
-    bool exit = false;
-    do {
-      exit = true;
-      for (uint32 i = 0; i < track_entries_size_; ++i) {
-        if (track_entries[i]->number() == track_num) {
-          track_num++;
-          exit = false;
-          break;
-        }
-      }
-    } while (!exit);
-  }
-  track->set_number(track_num);
-
-  track_entries_ = track_entries;
-  track_entries_[track_entries_size_] = track;
-  track_entries_size_ = count;
-  return true;
-}
-
-const Track* Tracks::GetTrackByIndex(uint32 index) const {
-  if (track_entries_ == NULL)
-    return NULL;
-
-  if (index >= track_entries_size_)
-    return NULL;
-
-  return track_entries_[index];
-}
-
-Track* Tracks::GetTrackByNumber(uint64 track_number) const {
-  const int32 count = track_entries_size();
-  for (int32 i = 0; i < count; ++i) {
-    if (track_entries_[i]->number() == track_number)
-      return track_entries_[i];
-  }
-
-  return NULL;
-}
-
-bool Tracks::TrackIsAudio(uint64 track_number) const {
-  const Track* const track = GetTrackByNumber(track_number);
-
-  if (track->type() == kAudio)
-    return true;
-
-  return false;
-}
-
-bool Tracks::TrackIsVideo(uint64 track_number) const {
-  const Track* const track = GetTrackByNumber(track_number);
-
-  if (track->type() == kVideo)
-    return true;
-
-  return false;
-}
-
-bool Tracks::Write(IMkvWriter* writer) const {
-  uint64 size = 0;
-  const int32 count = track_entries_size();
-  for (int32 i = 0; i < count; ++i) {
-    const Track* const track = GetTrackByIndex(i);
-
-    if (!track)
-      return false;
-
-    size += track->Size();
-  }
-
-  if (!WriteEbmlMasterElement(writer, kMkvTracks, size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  for (int32 i = 0; i < count; ++i) {
-    const Track* const track = GetTrackByIndex(i);
-    if (!track->Write(writer))
-      return false;
-  }
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Chapter Class
-
-bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
-
-void Chapter::set_time(const Segment& segment, uint64 start_ns, uint64 end_ns) {
-  const SegmentInfo* const info = segment.GetSegmentInfo();
-  const uint64 timecode_scale = info->timecode_scale();
-  start_timecode_ = start_ns / timecode_scale;
-  end_timecode_ = end_ns / timecode_scale;
-}
-
-bool Chapter::add_string(const char* title, const char* language,
-                         const char* country) {
-  if (!ExpandDisplaysArray())
-    return false;
-
-  Display& d = displays_[displays_count_++];
-  d.Init();
-
-  if (!d.set_title(title))
-    return false;
-
-  if (!d.set_language(language))
-    return false;
-
-  if (!d.set_country(country))
-    return false;
-
-  return true;
-}
-
-Chapter::Chapter() {
-  // This ctor only constructs the object.  Proper initialization is
-  // done in Init() (called in Chapters::AddChapter()).  The only
-  // reason we bother implementing this ctor is because we had to
-  // declare it as private (along with the dtor), in order to prevent
-  // clients from creating Chapter instances (a privelege we grant
-  // only to the Chapters class).  Doing no initialization here also
-  // means that creating arrays of chapter objects is more efficient,
-  // because we only initialize each new chapter object as it becomes
-  // active on the array.
-}
-
-Chapter::~Chapter() {}
-
-void Chapter::Init(unsigned int* seed) {
-  id_ = NULL;
-  start_timecode_ = 0;
-  end_timecode_ = 0;
-  displays_ = NULL;
-  displays_size_ = 0;
-  displays_count_ = 0;
-  uid_ = MakeUID(seed);
-}
-
-void Chapter::ShallowCopy(Chapter* dst) const {
-  dst->id_ = id_;
-  dst->start_timecode_ = start_timecode_;
-  dst->end_timecode_ = end_timecode_;
-  dst->uid_ = uid_;
-  dst->displays_ = displays_;
-  dst->displays_size_ = displays_size_;
-  dst->displays_count_ = displays_count_;
-}
-
-void Chapter::Clear() {
-  StrCpy(NULL, &id_);
-
-  while (displays_count_ > 0) {
-    Display& d = displays_[--displays_count_];
-    d.Clear();
-  }
-
-  delete[] displays_;
-  displays_ = NULL;
-
-  displays_size_ = 0;
-}
-
-bool Chapter::ExpandDisplaysArray() {
-  if (displays_size_ > displays_count_)
-    return true;  // nothing to do yet
-
-  const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
-
-  Display* const displays = new (std::nothrow) Display[size];  // NOLINT
-  if (displays == NULL)
-    return false;
-
-  for (int idx = 0; idx < displays_count_; ++idx) {
-    displays[idx] = displays_[idx];  // shallow copy
-  }
-
-  delete[] displays_;
-
-  displays_ = displays;
-  displays_size_ = size;
-
-  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_);
-
-  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;
-
-  if (writer == NULL)
-    return atom_size;
-
-  const int64 start = writer->Position();
-
-  if (!WriteEbmlMasterElement(writer, kMkvChapterAtom, payload_size))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvChapterStringUID, id_))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvChapterUID, uid_))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvChapterTimeStart, start_timecode_))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvChapterTimeEnd, end_timecode_))
-    return 0;
-
-  for (int idx = 0; idx < displays_count_; ++idx) {
-    const Display& d = displays_[idx];
-
-    if (!d.WriteDisplay(writer))
-      return 0;
-  }
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != atom_size)
-    return 0;
-
-  return atom_size;
-}
-
-void Chapter::Display::Init() {
-  title_ = NULL;
-  language_ = NULL;
-  country_ = NULL;
-}
-
-void Chapter::Display::Clear() {
-  StrCpy(NULL, &title_);
-  StrCpy(NULL, &language_);
-  StrCpy(NULL, &country_);
-}
-
-bool Chapter::Display::set_title(const char* title) {
-  return StrCpy(title, &title_);
-}
-
-bool Chapter::Display::set_language(const char* language) {
-  return StrCpy(language, &language_);
-}
-
-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_);
-
-  if (language_)
-    payload_size += EbmlElementSize(kMkvChapLanguage, language_);
-
-  if (country_)
-    payload_size += EbmlElementSize(kMkvChapCountry, country_);
-
-  const uint64 display_size =
-      EbmlMasterElementSize(kMkvChapterDisplay, payload_size) + payload_size;
-
-  if (writer == NULL)
-    return display_size;
-
-  const int64 start = writer->Position();
-
-  if (!WriteEbmlMasterElement(writer, kMkvChapterDisplay, payload_size))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvChapString, title_))
-    return 0;
-
-  if (language_) {
-    if (!WriteEbmlElement(writer, kMkvChapLanguage, language_))
-      return 0;
-  }
-
-  if (country_) {
-    if (!WriteEbmlElement(writer, kMkvChapCountry, country_))
-      return 0;
-  }
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != display_size)
-    return 0;
-
-  return display_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Chapters Class
-
-Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
-
-Chapters::~Chapters() {
-  while (chapters_count_ > 0) {
-    Chapter& chapter = chapters_[--chapters_count_];
-    chapter.Clear();
-  }
-
-  delete[] chapters_;
-  chapters_ = NULL;
-}
-
-int Chapters::Count() const { return chapters_count_; }
-
-Chapter* Chapters::AddChapter(unsigned int* seed) {
-  if (!ExpandChaptersArray())
-    return NULL;
-
-  Chapter& chapter = chapters_[chapters_count_++];
-  chapter.Init(seed);
-
-  return &chapter;
-}
-
-bool Chapters::Write(IMkvWriter* writer) const {
-  if (writer == NULL)
-    return false;
-
-  const uint64 payload_size = WriteEdition(NULL);  // return size only
-
-  if (!WriteEbmlMasterElement(writer, kMkvChapters, payload_size))
-    return false;
-
-  const int64 start = writer->Position();
-
-  if (WriteEdition(writer) == 0)  // error
-    return false;
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != payload_size)
-    return false;
-
-  return true;
-}
-
-bool Chapters::ExpandChaptersArray() {
-  if (chapters_size_ > chapters_count_)
-    return true;  // nothing to do yet
-
-  const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
-
-  Chapter* const chapters = new (std::nothrow) Chapter[size];  // NOLINT
-  if (chapters == NULL)
-    return false;
-
-  for (int idx = 0; idx < chapters_count_; ++idx) {
-    const Chapter& src = chapters_[idx];
-    Chapter* const dst = chapters + idx;
-    src.ShallowCopy(dst);
-  }
-
-  delete[] chapters_;
-
-  chapters_ = chapters;
-  chapters_size_ = size;
-
-  return true;
-}
-
-uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
-  uint64 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;
-
-  if (writer == NULL)  // return size only
-    return edition_size;
-
-  const int64 start = writer->Position();
-
-  if (!WriteEbmlMasterElement(writer, 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);
-    if (chapter_size == 0)  // error
-      return 0;
-  }
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != edition_size)
-    return 0;
-
-  return edition_size;
-}
-
-// Tag Class
-
-bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
-  if (!ExpandSimpleTagsArray())
-    return false;
-
-  SimpleTag& st = simple_tags_[simple_tags_count_++];
-  st.Init();
-
-  if (!st.set_tag_name(tag_name))
-    return false;
-
-  if (!st.set_tag_string(tag_string))
-    return false;
-
-  return true;
-}
-
-Tag::Tag() {
-  simple_tags_ = NULL;
-  simple_tags_size_ = 0;
-  simple_tags_count_ = 0;
-}
-
-Tag::~Tag() {}
-
-void Tag::ShallowCopy(Tag* dst) const {
-  dst->simple_tags_ = simple_tags_;
-  dst->simple_tags_size_ = simple_tags_size_;
-  dst->simple_tags_count_ = simple_tags_count_;
-}
-
-void Tag::Clear() {
-  while (simple_tags_count_ > 0) {
-    SimpleTag& st = simple_tags_[--simple_tags_count_];
-    st.Clear();
-  }
-
-  delete[] simple_tags_;
-  simple_tags_ = NULL;
-
-  simple_tags_size_ = 0;
-}
-
-bool Tag::ExpandSimpleTagsArray() {
-  if (simple_tags_size_ > simple_tags_count_)
-    return true;  // nothing to do yet
-
-  const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
-
-  SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size];  // NOLINT
-  if (simple_tags == NULL)
-    return false;
-
-  for (int idx = 0; idx < simple_tags_count_; ++idx) {
-    simple_tags[idx] = simple_tags_[idx];  // shallow copy
-  }
-
-  delete[] simple_tags_;
-
-  simple_tags_ = simple_tags;
-  simple_tags_size_ = size;
-
-  return true;
-}
-
-uint64 Tag::Write(IMkvWriter* writer) const {
-  uint64 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;
-
-  if (writer == NULL)
-    return tag_size;
-
-  const int64 start = writer->Position();
-
-  if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
-    return 0;
-
-  for (int idx = 0; idx < simple_tags_count_; ++idx) {
-    const SimpleTag& st = simple_tags_[idx];
-
-    if (!st.Write(writer))
-      return 0;
-  }
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != tag_size)
-    return 0;
-
-  return tag_size;
-}
-
-// Tag::SimpleTag
-
-void Tag::SimpleTag::Init() {
-  tag_name_ = NULL;
-  tag_string_ = NULL;
-}
-
-void Tag::SimpleTag::Clear() {
-  StrCpy(NULL, &tag_name_);
-  StrCpy(NULL, &tag_string_);
-}
-
-bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
-  return StrCpy(tag_name, &tag_name_);
-}
-
-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_);
-
-  payload_size += EbmlElementSize(kMkvTagString, tag_string_);
-
-  const uint64 simple_tag_size =
-      EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
-
-  if (writer == NULL)
-    return simple_tag_size;
-
-  const int64 start = writer->Position();
-
-  if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
-    return 0;
-
-  if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
-    return 0;
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != simple_tag_size)
-    return 0;
-
-  return simple_tag_size;
-}
-
-// Tags Class
-
-Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
-
-Tags::~Tags() {
-  while (tags_count_ > 0) {
-    Tag& tag = tags_[--tags_count_];
-    tag.Clear();
-  }
-
-  delete[] tags_;
-  tags_ = NULL;
-}
-
-int Tags::Count() const { return tags_count_; }
-
-Tag* Tags::AddTag() {
-  if (!ExpandTagsArray())
-    return NULL;
-
-  Tag& tag = tags_[tags_count_++];
-
-  return &tag;
-}
-
-bool Tags::Write(IMkvWriter* writer) const {
-  if (writer == NULL)
-    return false;
-
-  uint64 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))
-    return false;
-
-  const int64 start = writer->Position();
-
-  for (int idx = 0; idx < tags_count_; ++idx) {
-    const Tag& tag = tags_[idx];
-
-    const uint64 tag_size = tag.Write(writer);
-    if (tag_size == 0)  // error
-      return 0;
-  }
-
-  const int64 stop = writer->Position();
-
-  if (stop >= start && uint64(stop - start) != payload_size)
-    return false;
-
-  return true;
-}
-
-bool Tags::ExpandTagsArray() {
-  if (tags_size_ > tags_count_)
-    return true;  // nothing to do yet
-
-  const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
-
-  Tag* const tags = new (std::nothrow) Tag[size];  // NOLINT
-  if (tags == NULL)
-    return false;
-
-  for (int idx = 0; idx < tags_count_; ++idx) {
-    const Tag& src = tags_[idx];
-    Tag* const dst = tags + idx;
-    src.ShallowCopy(dst);
-  }
-
-  delete[] tags_;
-
-  tags_ = tags;
-  tags_size_ = size;
-
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Cluster class
-
-Cluster::Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale)
-    : blocks_added_(0),
-      finalized_(false),
-      header_written_(false),
-      payload_size_(0),
-      position_for_cues_(cues_pos),
-      size_position_(-1),
-      timecode_(timecode),
-      timecode_scale_(timecode_scale),
-      writer_(NULL) {}
-
-Cluster::~Cluster() {}
-
-bool Cluster::Init(IMkvWriter* ptr_writer) {
-  if (!ptr_writer) {
-    return false;
-  }
-  writer_ = ptr_writer;
-  return true;
-}
-
-bool Cluster::AddFrame(const Frame* const frame) { return DoWriteFrame(frame); }
-
-bool Cluster::AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                       uint64 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);
-}
-
-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) {
-  if (!additional || additional_length == 0) {
-    return false;
-  }
-  Frame frame;
-  if (!frame.Init(data, length) ||
-      !frame.AddAdditionalData(additional, additional_length, add_id)) {
-    return false;
-  }
-  frame.set_track_number(track_number);
-  frame.set_timestamp(abs_timecode);
-  frame.set_is_key(is_key);
-  return DoWriteFrame(&frame);
-}
-
-bool Cluster::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                         int64 discard_padding,
-                                         uint64 track_number,
-                                         uint64 abs_timecode, bool is_key) {
-  Frame frame;
-  if (!frame.Init(data, length))
-    return false;
-  frame.set_discard_padding(discard_padding);
-  frame.set_track_number(track_number);
-  frame.set_timestamp(abs_timecode);
-  frame.set_is_key(is_key);
-  return DoWriteFrame(&frame);
-}
-
-bool Cluster::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                          uint64 abs_timecode, uint64 duration_timecode) {
-  Frame frame;
-  if (!frame.Init(data, length))
-    return false;
-  frame.set_track_number(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);
-}
-
-void Cluster::AddPayloadSize(uint64 size) { payload_size_ += size; }
-
-bool Cluster::Finalize() {
-  if (!writer_ || finalized_ || size_position_ == -1)
-    return false;
-
-  if (writer_->Seekable()) {
-    const int64 pos = writer_->Position();
-
-    if (writer_->Position(size_position_))
-      return false;
-
-    if (WriteUIntSize(writer_, payload_size(), 8))
-      return false;
-
-    if (writer_->Position(pos))
-      return false;
-  }
-
-  finalized_ = true;
-
-  return true;
-}
-
-uint64 Cluster::Size() const {
-  const uint64 element_size =
-      EbmlMasterElementSize(kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) + payload_size_;
-  return element_size;
-}
-
-bool Cluster::PreWriteBlock() {
-  if (finalized_)
-    return false;
-
-  if (!header_written_) {
-    if (!WriteClusterHeader())
-      return false;
-  }
-
-  return true;
-}
-
-void Cluster::PostWriteBlock(uint64 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;
-
-  if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
-    return -1;
-
-  return rel_timecode;
-}
-
-bool Cluster::DoWriteFrame(const Frame* const frame) {
-  if (!frame || !frame->IsValid())
-    return false;
-
-  if (!PreWriteBlock())
-    return false;
-
-  const uint64 element_size = WriteFrame(writer_, frame, this);
-  if (element_size == 0)
-    return false;
-
-  PostWriteBlock(element_size);
-  return true;
-}
-
-bool Cluster::WriteClusterHeader() {
-  if (finalized_)
-    return false;
-
-  if (WriteID(writer_, kMkvCluster))
-    return false;
-
-  // Save for later.
-  size_position_ = writer_->Position();
-
-  // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
-  // bytes because we do not know how big our cluster will be.
-  if (SerializeInt(writer_, kEbmlUnknownValue, 8))
-    return false;
-
-  if (!WriteEbmlElement(writer_, kMkvTimecode, timecode()))
-    return false;
-  AddPayloadSize(EbmlElementSize(kMkvTimecode, timecode()));
-  header_written_ = true;
-
-  return true;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// SeekHead Class
-
-SeekHead::SeekHead() : start_pos_(0ULL) {
-  for (int32 i = 0; i < kSeekEntryCount; ++i) {
-    seek_entry_id_[i] = 0;
-    seek_entry_pos_[i] = 0;
-  }
-}
-
-SeekHead::~SeekHead() {}
-
-bool SeekHead::Finalize(IMkvWriter* writer) const {
-  if (writer->Seekable()) {
-    if (start_pos_ == -1)
-      return false;
-
-    uint64 payload_size = 0;
-    uint64 entry_size[kSeekEntryCount];
-
-    for (int32 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]);
-
-        payload_size +=
-            EbmlMasterElementSize(kMkvSeek, entry_size[i]) + entry_size[i];
-      }
-    }
-
-    // No SeekHead elements
-    if (payload_size == 0)
-      return true;
-
-    const int64 pos = writer->Position();
-    if (writer->Position(start_pos_))
-      return false;
-
-    if (!WriteEbmlMasterElement(writer, kMkvSeekHead, payload_size))
-      return false;
-
-    for (int32 i = 0; i < kSeekEntryCount; ++i) {
-      if (seek_entry_id_[i] != 0) {
-        if (!WriteEbmlMasterElement(writer, kMkvSeek, entry_size[i]))
-          return false;
-
-        if (!WriteEbmlElement(writer, kMkvSeekID,
-                              static_cast<uint64>(seek_entry_id_[i])))
-          return false;
-
-        if (!WriteEbmlElement(writer, kMkvSeekPosition, seek_entry_pos_[i]))
-          return false;
-      }
-    }
-
-    const uint64 total_entry_size = kSeekEntryCount * MaxEntrySize();
-    const uint64 total_size =
-        EbmlMasterElementSize(kMkvSeekHead, total_entry_size) +
-        total_entry_size;
-    const int64 size_left = total_size - (writer->Position() - start_pos_);
-
-    const uint64 bytes_written = WriteVoidElement(writer, size_left);
-    if (!bytes_written)
-      return false;
-
-    if (writer->Position(pos))
-      return false;
-  }
-
-  return true;
-}
-
-bool SeekHead::Write(IMkvWriter* writer) {
-  const uint64 entry_size = kSeekEntryCount * MaxEntrySize();
-  const uint64 size = EbmlMasterElementSize(kMkvSeekHead, entry_size);
-
-  start_pos_ = writer->Position();
-
-  const uint64 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) {
-    if (seek_entry_id_[i] == 0) {
-      seek_entry_id_[i] = id;
-      seek_entry_pos_[i] = pos;
-      return true;
-    }
-  }
-  return false;
-}
-
-uint32 SeekHead::GetId(int index) const {
-  if (index < 0 || index >= kSeekEntryCount)
-    return UINT_MAX;
-  return seek_entry_id_[index];
-}
-
-uint64 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) {
-  if (index < 0 || index >= kSeekEntryCount)
-    return false;
-  seek_entry_id_[index] = id;
-  seek_entry_pos_[index] = 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) +
-      max_entry_payload_size;
-
-  return max_entry_size;
-}
-
-///////////////////////////////////////////////////////////////
-//
-// SegmentInfo Class
-
-SegmentInfo::SegmentInfo()
-    : duration_(-1.0),
-      muxing_app_(NULL),
-      timecode_scale_(1000000ULL),
-      writing_app_(NULL),
-      date_utc_(LLONG_MIN),
-      duration_pos_(-1) {}
-
-SegmentInfo::~SegmentInfo() {
-  delete[] muxing_app_;
-  delete[] writing_app_;
-}
-
-bool SegmentInfo::Init() {
-  int32 major;
-  int32 minor;
-  int32 build;
-  int32 revision;
-  GetVersion(&major, &minor, &build, &revision);
-  char temp[256];
-#ifdef _MSC_VER
-  sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
-            minor, build, revision);
-#else
-  snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
-           minor, build, revision);
-#endif
-
-  const size_t app_len = strlen(temp) + 1;
-
-  delete[] muxing_app_;
-
-  muxing_app_ = new (std::nothrow) char[app_len];  // NOLINT
-  if (!muxing_app_)
-    return false;
-
-#ifdef _MSC_VER
-  strcpy_s(muxing_app_, app_len, temp);
-#else
-  strcpy(muxing_app_, temp);
-#endif
-
-  set_writing_app(temp);
-  if (!writing_app_)
-    return false;
-  return true;
-}
-
-bool SegmentInfo::Finalize(IMkvWriter* writer) const {
-  if (!writer)
-    return false;
-
-  if (duration_ > 0.0) {
-    if (writer->Seekable()) {
-      if (duration_pos_ == -1)
-        return false;
-
-      const int64 pos = writer->Position();
-
-      if (writer->Position(duration_pos_))
-        return false;
-
-      if (!WriteEbmlElement(writer, kMkvDuration,
-                            static_cast<float>(duration_)))
-        return false;
-
-      if (writer->Position(pos))
-        return false;
-    }
-  }
-
-  return true;
-}
-
-bool SegmentInfo::Write(IMkvWriter* writer) {
-  if (!writer || !muxing_app_ || !writing_app_)
-    return false;
-
-  uint64 size = EbmlElementSize(kMkvTimecodeScale, timecode_scale_);
-  if (duration_ > 0.0)
-    size += EbmlElementSize(kMkvDuration, static_cast<float>(duration_));
-  if (date_utc_ != LLONG_MIN)
-    size += EbmlDateElementSize(kMkvDateUTC);
-  size += EbmlElementSize(kMkvMuxingApp, muxing_app_);
-  size += EbmlElementSize(kMkvWritingApp, writing_app_);
-
-  if (!WriteEbmlMasterElement(writer, kMkvInfo, size))
-    return false;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return false;
-
-  if (!WriteEbmlElement(writer, kMkvTimecodeScale, timecode_scale_))
-    return false;
-
-  if (duration_ > 0.0) {
-    // Save for later
-    duration_pos_ = writer->Position();
-
-    if (!WriteEbmlElement(writer, kMkvDuration, static_cast<float>(duration_)))
-      return false;
-  }
-
-  if (date_utc_ != LLONG_MIN)
-    WriteEbmlDateElement(writer, kMkvDateUTC, date_utc_);
-
-  if (!WriteEbmlElement(writer, kMkvMuxingApp, muxing_app_))
-    return false;
-  if (!WriteEbmlElement(writer, kMkvWritingApp, writing_app_))
-    return false;
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(size))
-    return false;
-
-  return true;
-}
-
-void SegmentInfo::set_muxing_app(const char* app) {
-  if (app) {
-    const size_t length = strlen(app) + 1;
-    char* temp_str = new (std::nothrow) char[length];  // NOLINT
-    if (!temp_str)
-      return;
-
-#ifdef _MSC_VER
-    strcpy_s(temp_str, length, app);
-#else
-    strcpy(temp_str, app);
-#endif
-
-    delete[] muxing_app_;
-    muxing_app_ = temp_str;
-  }
-}
-
-void SegmentInfo::set_writing_app(const char* app) {
-  if (app) {
-    const size_t length = strlen(app) + 1;
-    char* temp_str = new (std::nothrow) char[length];  // NOLINT
-    if (!temp_str)
-      return;
-
-#ifdef _MSC_VER
-    strcpy_s(temp_str, length, app);
-#else
-    strcpy(temp_str, app);
-#endif
-
-    delete[] writing_app_;
-    writing_app_ = temp_str;
-  }
-}
-
-///////////////////////////////////////////////////////////////
-//
-// Segment Class
-
-Segment::Segment()
-    : chunk_count_(0),
-      chunk_name_(NULL),
-      chunk_writer_cluster_(NULL),
-      chunk_writer_cues_(NULL),
-      chunk_writer_header_(NULL),
-      chunking_(false),
-      chunking_base_name_(NULL),
-      cluster_list_(NULL),
-      cluster_list_capacity_(0),
-      cluster_list_size_(0),
-      cues_position_(kAfterClusters),
-      cues_track_(0),
-      force_new_cluster_(false),
-      frames_(NULL),
-      frames_capacity_(0),
-      frames_size_(0),
-      has_video_(false),
-      header_written_(false),
-      last_block_duration_(0),
-      last_timestamp_(0),
-      max_cluster_duration_(kDefaultMaxClusterDuration),
-      max_cluster_size_(0),
-      mode_(kFile),
-      new_cuepoint_(false),
-      output_cues_(true),
-      payload_pos_(0),
-      size_position_(0),
-      doc_type_version_(kDefaultDocTypeVersion),
-      doc_type_version_written_(0),
-      writer_cluster_(NULL),
-      writer_cues_(NULL),
-      writer_header_(NULL) {
-  const time_t curr_time = time(NULL);
-  seed_ = static_cast<unsigned int>(curr_time);
-#ifdef _WIN32
-  srand(seed_);
-#endif
-}
-
-Segment::~Segment() {
-  if (cluster_list_) {
-    for (int32 i = 0; i < cluster_list_size_; ++i) {
-      Cluster* const cluster = cluster_list_[i];
-      delete cluster;
-    }
-    delete[] cluster_list_;
-  }
-
-  if (frames_) {
-    for (int32 i = 0; i < frames_size_; ++i) {
-      Frame* const frame = frames_[i];
-      delete frame;
-    }
-    delete[] frames_;
-  }
-
-  delete[] chunk_name_;
-  delete[] chunking_base_name_;
-
-  if (chunk_writer_cluster_) {
-    chunk_writer_cluster_->Close();
-    delete chunk_writer_cluster_;
-  }
-  if (chunk_writer_cues_) {
-    chunk_writer_cues_->Close();
-    delete chunk_writer_cues_;
-  }
-  if (chunk_writer_header_) {
-    chunk_writer_header_->Close();
-    delete chunk_writer_header_;
-  }
-}
-
-void Segment::MoveCuesBeforeClustersHelper(uint64 diff, int32 index,
-                                           uint64* 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;
-  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
-  //    Let b = Increase in Cue Point's size due to this iteration
-  //    Let c = Increase in size of Cues Element's length due to this iteration
-  //            (This is computed as CodedSize(a + b) - CodedSize(a))
-  //    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 =
-      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) {
-      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)
-    cue_size += cues_.GetCueByIndex(i)->Size();
-  for (int32 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)
-      cluster_index = i;
-    if (seek_head_.GetId(i) == kMkvCues)
-      cues_index = i;
-  }
-  seek_head_.SetSeekEntry(cues_index, kMkvCues,
-                          seek_head_.GetPosition(cluster_index));
-  seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
-                          cues_.Size() + seek_head_.GetPosition(cues_index));
-}
-
-bool Segment::Init(IMkvWriter* ptr_writer) {
-  if (!ptr_writer) {
-    return false;
-  }
-  writer_cluster_ = ptr_writer;
-  writer_cues_ = ptr_writer;
-  writer_header_ = ptr_writer;
-  return segment_info_.Init();
-}
-
-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);
-
-  // Copy the headers.
-  if (!ChunkedCopy(reader, writer, 0, cluster_offset))
-    return false;
-
-  // Recompute cue positions and seek entries.
-  MoveCuesBeforeClusters();
-
-  // Write cues and seek entries.
-  // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
-  // second time with a different writer object. But the name Finalize() doesn't
-  // indicate something we want to call more than once. So consider renaming it
-  // to write() or some such.
-  if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
-    return false;
-
-  // Copy the Clusters.
-  if (!ChunkedCopy(reader, writer, cluster_offset,
-                   cluster_end_offset_ - cluster_offset))
-    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_;
-  if (writer->Position(size_position_) ||
-      WriteUIntSize(writer, segment_size, 8) || writer->Position(pos))
-    return false;
-  return true;
-}
-
-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 (!old_cluster || !old_cluster->Finalize())
-        return false;
-    }
-
-    if (chunking_ && chunk_writer_cluster_) {
-      chunk_writer_cluster_->Close();
-      chunk_count_++;
-    }
-
-    const double duration =
-        (static_cast<double>(last_timestamp_) + last_block_duration_) /
-        segment_info_.timecode_scale();
-    segment_info_.set_duration(duration);
-    if (!segment_info_.Finalize(writer_header_))
-      return false;
-
-    if (output_cues_)
-      if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
-        return false;
-
-    if (chunking_) {
-      if (!chunk_writer_cues_)
-        return false;
-
-      char* name = NULL;
-      if (!UpdateChunkName("cues", &name))
-        return false;
-
-      const bool cues_open = chunk_writer_cues_->Open(name);
-      delete[] name;
-      if (!cues_open)
-        return false;
-    }
-
-    cluster_end_offset_ = writer_cluster_->Position();
-
-    // Write the seek headers and cues
-    if (output_cues_)
-      if (!cues_.Write(writer_cues_))
-        return false;
-
-    if (!seek_head_.Finalize(writer_header_))
-      return false;
-
-    if (writer_header_->Seekable()) {
-      if (size_position_ == -1)
-        return false;
-
-      const int64 segment_size = MaxOffset();
-      if (segment_size < 1)
-        return false;
-
-      const int64 pos = writer_header_->Position();
-      UpdateDocTypeVersion();
-      if (doc_type_version_ != doc_type_version_written_) {
-        if (writer_header_->Position(0))
-          return false;
-
-        if (!WriteEbmlHeader(writer_header_, doc_type_version_))
-          return false;
-        if (writer_header_->Position() != ebml_header_size_)
-          return false;
-
-        doc_type_version_written_ = doc_type_version_;
-      }
-
-      if (writer_header_->Position(size_position_))
-        return false;
-
-      if (WriteUIntSize(writer_header_, segment_size, 8))
-        return false;
-
-      if (writer_header_->Position(pos))
-        return false;
-    }
-
-    if (chunking_) {
-      // Do not close any writers until the segment size has been written,
-      // otherwise the size may be off.
-      if (!chunk_writer_cues_ || !chunk_writer_header_)
-        return false;
-
-      chunk_writer_cues_->Close();
-      chunk_writer_header_->Close();
-    }
-  }
-
-  return true;
-}
-
-Track* Segment::AddTrack(int32 number) {
-  Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
-
-  if (!track)
-    return NULL;
-
-  if (!tracks_.AddTrack(track, number)) {
-    delete track;
-    return NULL;
-  }
-
-  return track;
-}
-
-Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
-
-Tag* Segment::AddTag() { return tags_.AddTag(); }
-
-uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
-  VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_);  // NOLINT
-  if (!track)
-    return 0;
-
-  track->set_type(Tracks::kVideo);
-  track->set_codec_id(Tracks::kVp8CodecId);
-  track->set_width(width);
-  track->set_height(height);
-
-  tracks_.AddTrack(track, number);
-  has_video_ = true;
-
-  return track->number();
-}
-
-bool Segment::AddCuePoint(uint64 timestamp, uint64 track) {
-  if (cluster_list_size_ < 1)
-    return false;
-
-  const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
-  if (!cluster)
-    return false;
-
-  CuePoint* const cue = new (std::nothrow) CuePoint();  // NOLINT
-  if (!cue)
-    return false;
-
-  cue->set_time(timestamp / segment_info_.timecode_scale());
-  cue->set_block_number(cluster->blocks_added());
-  cue->set_cluster_pos(cluster->position_for_cues());
-  cue->set_track(track);
-  if (!cues_.AddCue(cue))
-    return false;
-
-  new_cuepoint_ = false;
-  return true;
-}
-
-uint64 Segment::AddAudioTrack(int32 sample_rate, int32 channels, int32 number) {
-  AudioTrack* const track = new (std::nothrow) AudioTrack(&seed_);  // NOLINT
-  if (!track)
-    return 0;
-
-  track->set_type(Tracks::kAudio);
-  track->set_codec_id(Tracks::kVorbisCodecId);
-  track->set_sample_rate(sample_rate);
-  track->set_channels(channels);
-
-  tracks_.AddTrack(track, number);
-
-  return track->number();
-}
-
-bool Segment::AddFrame(const uint8* data, uint64 length, uint64 track_number,
-                       uint64 timestamp, bool is_key) {
-  if (!data)
-    return false;
-
-  Frame frame;
-  if (!frame.Init(data, length))
-    return false;
-  frame.set_track_number(track_number);
-  frame.set_timestamp(timestamp);
-  frame.set_is_key(is_key);
-  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) {
-  if (!data || !additional)
-    return false;
-
-  Frame frame;
-  if (!frame.Init(data, length) ||
-      !frame.AddAdditionalData(additional, additional_length, add_id)) {
-    return false;
-  }
-  frame.set_track_number(track_number);
-  frame.set_timestamp(timestamp);
-  frame.set_is_key(is_key);
-  return AddGenericFrame(&frame);
-}
-
-bool Segment::AddFrameWithDiscardPadding(const uint8* data, uint64 length,
-                                         int64 discard_padding,
-                                         uint64 track_number, uint64 timestamp,
-                                         bool is_key) {
-  if (!data)
-    return false;
-
-  Frame frame;
-  if (!frame.Init(data, length))
-    return false;
-  frame.set_discard_padding(discard_padding);
-  frame.set_track_number(track_number);
-  frame.set_timestamp(timestamp);
-  frame.set_is_key(is_key);
-  return AddGenericFrame(&frame);
-}
-
-bool Segment::AddMetadata(const uint8* data, uint64 length, uint64 track_number,
-                          uint64 timestamp_ns, uint64 duration_ns) {
-  if (!data)
-    return false;
-
-  Frame frame;
-  if (!frame.Init(data, length))
-    return false;
-  frame.set_track_number(track_number);
-  frame.set_timestamp(timestamp_ns);
-  frame.set_duration(duration_ns);
-  frame.set_is_key(true);  // All metadata blocks are keyframes.
-  return AddGenericFrame(&frame);
-}
-
-bool Segment::AddGenericFrame(const Frame* frame) {
-  if (!frame)
-    return false;
-
-  if (!CheckHeaderInfo())
-    return false;
-
-  // Check for non-monotonically increasing timestamps.
-  if (frame->timestamp() < last_timestamp_)
-    return false;
-
-  // Check if the track number is valid.
-  if (!tracks_.GetTrackByNumber(frame->track_number()))
-    return false;
-
-  if (frame->discard_padding() != 0)
-    doc_type_version_ = 4;
-
-  // If the segment has a video track hold onto audio frames to make sure the
-  // audio that is associated with the start time of a video key-frame is
-  // muxed into the same cluster.
-  if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
-      !force_new_cluster_) {
-    Frame* const new_frame = new (std::nothrow) Frame();
-    if (!new_frame || !new_frame->CopyFrom(*frame))
-      return false;
-    return QueueFrame(new_frame);
-  }
-
-  if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
-                              frame->is_key())) {
-    return false;
-  }
-
-  if (cluster_list_size_ < 1)
-    return false;
-
-  Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
-  if (!cluster)
-    return false;
-
-  // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
-  // if it is not set already.
-  bool frame_created = false;
-  if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
-      !frame->reference_block_timestamp_set()) {
-    Frame* const new_frame = new (std::nothrow) Frame();
-    if (!new_frame->CopyFrom(*frame))
-      return false;
-    new_frame->set_reference_block_timestamp(
-        last_track_timestamp_[frame->track_number() - 1]);
-    frame = new_frame;
-    frame_created = true;
-  }
-
-  if (!cluster->AddFrame(frame))
-    return false;
-
-  if (new_cuepoint_ && cues_track_ == frame->track_number()) {
-    if (!AddCuePoint(frame->timestamp(), cues_track_))
-      return false;
-  }
-
-  last_timestamp_ = frame->timestamp();
-  last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
-  last_block_duration_ = frame->duration();
-
-  if (frame_created)
-    delete frame;
-
-  return true;
-}
-
-void Segment::OutputCues(bool output_cues) { output_cues_ = output_cues; }
-
-bool Segment::SetChunking(bool chunking, const char* filename) {
-  if (chunk_count_ > 0)
-    return false;
-
-  if (chunking) {
-    if (!filename)
-      return false;
-
-    // Check if we are being set to what is already set.
-    if (chunking_ && !strcmp(filename, chunking_base_name_))
-      return true;
-
-    const size_t name_length = strlen(filename) + 1;
-    char* const temp = new (std::nothrow) char[name_length];  // NOLINT
-    if (!temp)
-      return false;
-
-#ifdef _MSC_VER
-    strcpy_s(temp, name_length, filename);
-#else
-    strcpy(temp, filename);
-#endif
-
-    delete[] chunking_base_name_;
-    chunking_base_name_ = temp;
-
-    if (!UpdateChunkName("chk", &chunk_name_))
-      return false;
-
-    if (!chunk_writer_cluster_) {
-      chunk_writer_cluster_ = new (std::nothrow) MkvWriter();  // NOLINT
-      if (!chunk_writer_cluster_)
-        return false;
-    }
-
-    if (!chunk_writer_cues_) {
-      chunk_writer_cues_ = new (std::nothrow) MkvWriter();  // NOLINT
-      if (!chunk_writer_cues_)
-        return false;
-    }
-
-    if (!chunk_writer_header_) {
-      chunk_writer_header_ = new (std::nothrow) MkvWriter();  // NOLINT
-      if (!chunk_writer_header_)
-        return false;
-    }
-
-    if (!chunk_writer_cluster_->Open(chunk_name_))
-      return false;
-
-    const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
-    char* const header = new (std::nothrow) char[header_length];  // NOLINT
-    if (!header)
-      return false;
-
-#ifdef _MSC_VER
-    strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
-    strcat_s(header, header_length, ".hdr");
-#else
-    strcpy(header, chunking_base_name_);
-    strcat(header, ".hdr");
-#endif
-    if (!chunk_writer_header_->Open(header)) {
-      delete[] header;
-      return false;
-    }
-
-    writer_cluster_ = chunk_writer_cluster_;
-    writer_cues_ = chunk_writer_cues_;
-    writer_header_ = chunk_writer_header_;
-
-    delete[] header;
-  }
-
-  chunking_ = chunking;
-
-  return true;
-}
-
-bool Segment::CuesTrack(uint64 track_number) {
-  const Track* const track = GetTrackByNumber(track_number);
-  if (!track)
-    return false;
-
-  cues_track_ = track_number;
-  return true;
-}
-
-void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
-
-Track* Segment::GetTrackByNumber(uint64 track_number) const {
-  return tracks_.GetTrackByNumber(track_number);
-}
-
-bool Segment::WriteSegmentHeader() {
-  UpdateDocTypeVersion();
-
-  // TODO(fgalligan): Support more than one segment.
-  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());
-
-  // 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))
-    return false;
-
-  // Save for later.
-  size_position_ = writer_header_->Position();
-
-  // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
-  // bytes because if we are going to overwrite the segment size later we do
-  // not know how big our segment will be.
-  if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
-    return false;
-
-  payload_pos_ = writer_header_->Position();
-
-  if (mode_ == kFile && writer_header_->Seekable()) {
-    // Set the duration > 0.0 so SegmentInfo will write out the duration. When
-    // the muxer is done writing we will set the correct duration and have
-    // SegmentInfo upadte it.
-    segment_info_.set_duration(1.0);
-
-    if (!seek_head_.Write(writer_header_))
-      return false;
-  }
-
-  if (!seek_head_.AddSeekEntry(kMkvInfo, MaxOffset()))
-    return false;
-  if (!segment_info_.Write(writer_header_))
-    return false;
-
-  if (!seek_head_.AddSeekEntry(kMkvTracks, MaxOffset()))
-    return false;
-  if (!tracks_.Write(writer_header_))
-    return false;
-
-  if (chapters_.Count() > 0) {
-    if (!seek_head_.AddSeekEntry(kMkvChapters, MaxOffset()))
-      return false;
-    if (!chapters_.Write(writer_header_))
-      return false;
-  }
-
-  if (tags_.Count() > 0) {
-    if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
-      return false;
-    if (!tags_.Write(writer_header_))
-      return false;
-  }
-
-  if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
-    if (!chunk_writer_header_)
-      return false;
-
-    chunk_writer_header_->Close();
-  }
-
-  header_written_ = true;
-
-  return true;
-}
-
-// 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,
-                       bool is_key) const {
-  if (force_new_cluster_)
-    return 1;
-
-  // If no clusters have been created yet, then create a new cluster
-  // and write this frame immediately, in the new cluster.  This path
-  // should only be followed once, the first time we attempt to write
-  // a frame.
-
-  if (cluster_list_size_ <= 0)
-    return 1;
-
-  // There exists at least one cluster. We must compare the frame to
-  // the last cluster, in order to determine whether the frame is
-  // 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 Cluster* const last_cluster = cluster_list_[cluster_list_size_ - 1];
-  const uint64 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
-  // is allowed, this muxer doesn't actually write clusters like that,
-  // so this indicates a bug somewhere in our algorithm.
-
-  if (frame_timecode < last_cluster_timecode)  // should never happen
-    return -1;
-
-  // If the frame has a timestamp significantly larger than the last
-  // cluster (in Matroska, cluster-relative timestamps are serialized
-  // 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;
-
-  if (delta_timecode > kMaxBlockTimecode)
-    return 2;
-
-  // We decide to create a new cluster when we have a video keyframe.
-  // This will flush queued (audio) frames, and write the keyframe
-  // immediately, in the newly-created cluster.
-
-  if (is_key && tracks_.TrackIsVideo(track_number))
-    return 1;
-
-  // Create a new cluster if we have accumulated too many frames
-  // 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;
-
-  if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
-    return 1;
-
-  // This is similar to the case above, with the difference that a new
-  // cluster is created when the size of the current cluster exceeds a
-  // threshold.
-
-  const uint64 cluster_size = last_cluster->payload_size();
-
-  if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
-    return 1;
-
-  // There's no need to create a new cluster, so emit this frame now.
-
-  return 0;
-}
-
-bool Segment::MakeNewCluster(uint64 frame_timestamp_ns) {
-  const int32 new_size = cluster_list_size_ + 1;
-
-  if (new_size > cluster_list_capacity_) {
-    // Add more clusters.
-    const int32 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) {
-      clusters[i] = cluster_list_[i];
-    }
-
-    delete[] cluster_list_;
-
-    cluster_list_ = clusters;
-    cluster_list_capacity_ = new_capacity;
-  }
-
-  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 (!old_cluster || !old_cluster->Finalize())
-        return false;
-    }
-
-    if (output_cues_)
-      new_cuepoint_ = true;
-  }
-
-  if (chunking_ && cluster_list_size_ > 0) {
-    chunk_writer_cluster_->Close();
-    chunk_count_++;
-
-    if (!UpdateChunkName("chk", &chunk_name_))
-      return false;
-    if (!chunk_writer_cluster_->Open(chunk_name_))
-      return false;
-  }
-
-  const uint64 timecode_scale = segment_info_.timecode_scale();
-  const uint64 frame_timecode = frame_timestamp_ns / timecode_scale;
-
-  uint64 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;
-
-    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());
-  if (!cluster)
-    return false;
-
-  if (!cluster->Init(writer_cluster_))
-    return false;
-
-  cluster_list_size_ = new_size;
-  return true;
-}
-
-bool Segment::DoNewClusterProcessing(uint64 track_number,
-                                     uint64 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.
-    const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
-    if (result < 0)  // error
-      return false;
-
-    // Always set force_new_cluster_ to false after TestFrame.
-    force_new_cluster_ = false;
-
-    // A non-zero result means create a new cluster.
-    if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
-      return false;
-
-    // Write queued (audio) frames.
-    const int frame_count = WriteFramesAll();
-    if (frame_count < 0)  // error
-      return false;
-
-    // Write the current frame to the current cluster (if TestFrame
-    // returns 0) or to a newly created cluster (TestFrame returns 1).
-    if (result <= 1)
-      return true;
-
-    // TestFrame returned 2, which means there was a large time
-    // difference between the cluster and the frame itself.  Do the
-    // test again, comparing the frame to the new cluster.
-  }
-}
-
-bool Segment::CheckHeaderInfo() {
-  if (!header_written_) {
-    if (!WriteSegmentHeader())
-      return false;
-
-    if (!seek_head_.AddSeekEntry(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) {
-        const Track* const track = tracks_.GetTrackByIndex(i);
-        if (!track)
-          return false;
-
-        if (tracks_.TrackIsVideo(track->number())) {
-          cues_track_ = track->number();
-          break;
-        }
-      }
-
-      // Set first track found
-      if (cues_track_ == 0) {
-        const Track* const track = tracks_.GetTrackByIndex(0);
-        if (!track)
-          return false;
-
-        cues_track_ = track->number();
-      }
-    }
-  }
-  return true;
-}
-
-void Segment::UpdateDocTypeVersion() {
-  for (uint32 index = 0; index < tracks_.track_entries_size(); ++index) {
-    const Track* track = tracks_.GetTrackByIndex(index);
-    if (track == NULL)
-      break;
-    if ((track->codec_delay() || track->seek_pre_roll()) &&
-        doc_type_version_ < 4) {
-      doc_type_version_ = 4;
-      break;
-    }
-  }
-}
-
-bool Segment::UpdateChunkName(const char* ext, char** name) const {
-  if (!name || !ext)
-    return false;
-
-  char ext_chk[64];
-#ifdef _MSC_VER
-  sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
-#else
-  snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
-#endif
-
-  const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
-  char* const str = new (std::nothrow) char[length];  // NOLINT
-  if (!str)
-    return false;
-
-#ifdef _MSC_VER
-  strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
-  strcat_s(str, length, ext_chk);
-#else
-  strcpy(str, chunking_base_name_);
-  strcat(str, ext_chk);
-#endif
-
-  delete[] * name;
-  *name = str;
-
-  return true;
-}
-
-int64 Segment::MaxOffset() {
-  if (!writer_header_)
-    return -1;
-
-  int64 offset = writer_header_->Position() - payload_pos_;
-
-  if (chunking_) {
-    for (int32 i = 0; i < cluster_list_size_; ++i) {
-      Cluster* const cluster = cluster_list_[i];
-      offset += cluster->Size();
-    }
-
-    if (writer_cues_)
-      offset += writer_cues_->Position();
-  }
-
-  return offset;
-}
-
-bool Segment::QueueFrame(Frame* frame) {
-  const int32 new_size = frames_size_ + 1;
-
-  if (new_size > frames_capacity_) {
-    // Add more frames.
-    const int32 new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
-
-    if (new_capacity < 1)
-      return false;
-
-    Frame** const frames = new (std::nothrow) Frame*[new_capacity];  // NOLINT
-    if (!frames)
-      return false;
-
-    for (int32 i = 0; i < frames_size_; ++i) {
-      frames[i] = frames_[i];
-    }
-
-    delete[] frames_;
-    frames_ = frames;
-    frames_capacity_ = new_capacity;
-  }
-
-  frames_[frames_size_++] = frame;
-
-  return true;
-}
-
-int Segment::WriteFramesAll() {
-  if (frames_ == NULL)
-    return 0;
-
-  if (cluster_list_size_ < 1)
-    return -1;
-
-  Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
-
-  if (!cluster)
-    return -1;
-
-  for (int32 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.
-    if (frame->discard_padding() != 0)
-      doc_type_version_ = 4;
-    if (!cluster->AddFrame(frame))
-      return -1;
-
-    if (new_cuepoint_ && cues_track_ == frame->track_number()) {
-      if (!AddCuePoint(frame->timestamp(), cues_track_))
-        return -1;
-    }
-
-    if (frame->timestamp() > last_timestamp_) {
-      last_timestamp_ = frame->timestamp();
-      last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
-    }
-
-    delete frame;
-    frame = NULL;
-  }
-
-  const int result = frames_size_;
-  frames_size_ = 0;
-
-  return result;
-}
-
-bool Segment::WriteFramesLessThan(uint64 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.
-  if (frames_size_ > 0 && cluster_list_size_ > 0) {
-    if (!frames_)
-      return false;
-
-    Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
-    if (!cluster)
-      return false;
-
-    int32 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) {
-      const Frame* const frame_curr = frames_[i];
-
-      if (frame_curr->timestamp() > timestamp)
-        break;
-
-      const Frame* const frame_prev = frames_[i - 1];
-      if (frame_prev->discard_padding() != 0)
-        doc_type_version_ = 4;
-      if (!cluster->AddFrame(frame_prev))
-        return false;
-
-      if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
-        if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
-          return false;
-      }
-
-      ++shift_left;
-      if (frame_prev->timestamp() > last_timestamp_) {
-        last_timestamp_ = frame_prev->timestamp();
-        last_track_timestamp_[frame_prev->track_number() - 1] =
-            frame_prev->timestamp();
-      }
-
-      delete frame_prev;
-    }
-
-    if (shift_left > 0) {
-      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) {
-        frames_[i] = frames_[i + shift_left];
-      }
-
-      frames_size_ = new_frames_size;
-    }
-  }
-
-  return true;
-}
-
-}  // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxer.cc b/third_party/libwebm/mkvmuxer/mkvmuxer.cc
new file mode 100644
index 0000000..c79ce24
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.cc
@@ -0,0 +1,3769 @@
+// 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.
+
+#include "mkvmuxer/mkvmuxer.h"
+
+#include <cfloat>
+#include <climits>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <memory>
+#include <new>
+#include <vector>
+
+#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
+// |dst| copy (hence the caller is responsible for eventually
+// deallocating the strings, either directly, or indirectly via
+// StrCpy).  Returns true if the source string was successfully copied
+// to the destination.
+bool StrCpy(const char* src, char** dst_ptr) {
+  if (dst_ptr == NULL)
+    return false;
+
+  char*& dst = *dst_ptr;
+
+  delete[] dst;
+  dst = NULL;
+
+  if (src == NULL)
+    return true;
+
+  const size_t size = strlen(src) + 1;
+
+  dst = new (std::nothrow) char[size];  // NOLINT
+  if (dst == NULL)
+    return false;
+
+  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
+
+///////////////////////////////////////////////////////////////
+//
+// IMkvWriter Class
+
+IMkvWriter::IMkvWriter() {}
+
+IMkvWriter::~IMkvWriter() {}
+
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_t doc_type_version) {
+  // Level 0
+  uint64_t size = EbmlElementSize(libwebm::kMkvEBMLVersion, UINT64_C(1));
+  size += EbmlElementSize(libwebm::kMkvEBMLReadVersion, UINT64_C(1));
+  size += EbmlElementSize(libwebm::kMkvEBMLMaxIDLength, UINT64_C(4));
+  size += EbmlElementSize(libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8));
+  size += EbmlElementSize(libwebm::kMkvDocType, "webm");
+  size += EbmlElementSize(libwebm::kMkvDocTypeVersion, doc_type_version);
+  size += EbmlElementSize(libwebm::kMkvDocTypeReadVersion, UINT64_C(2));
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvEBML, size))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLVersion, UINT64_C(1)))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLReadVersion, UINT64_C(1)))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxIDLength, UINT64_C(4)))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvEBMLMaxSizeLength, UINT64_C(8)))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocType, "webm"))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeVersion, doc_type_version))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvDocTypeReadVersion, UINT64_C(2)))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlHeader(IMkvWriter* writer) {
+  return WriteEbmlHeader(writer, mkvmuxer::Segment::kDefaultDocTypeVersion);
+}
+
+bool ChunkedCopy(mkvparser::IMkvReader* source, mkvmuxer::IMkvWriter* dst,
+                 int64_t start, int64_t size) {
+  // TODO(vigneshv): Check if this is a reasonable value.
+  const uint32_t kBufSize = 2048;
+  uint8_t* buf = new uint8_t[kBufSize];
+  int64_t offset = start;
+  while (size > 0) {
+    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_t>(read_len));
+    offset += read_len;
+    size -= read_len;
+  }
+  delete[] buf;
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Frame Class
+
+Frame::Frame()
+    : add_id_(0),
+      additional_(NULL),
+      additional_length_(0),
+      duration_(0),
+      duration_set_(false),
+      frame_(NULL),
+      is_key_(false),
+      length_(0),
+      track_number_(0),
+      timestamp_(0),
+      discard_padding_(0),
+      reference_block_timestamp_(0),
+      reference_block_timestamp_set_(false) {}
+
+Frame::~Frame() {
+  delete[] frame_;
+  delete[] additional_;
+}
+
+bool Frame::CopyFrom(const Frame& frame) {
+  delete[] frame_;
+  frame_ = NULL;
+  length_ = 0;
+  if (frame.length() > 0 && frame.frame() != NULL &&
+      !Init(frame.frame(), frame.length())) {
+    return false;
+  }
+  add_id_ = 0;
+  delete[] additional_;
+  additional_ = NULL;
+  additional_length_ = 0;
+  if (frame.additional_length() > 0 && frame.additional() != NULL &&
+      !AddAdditionalData(frame.additional(), frame.additional_length(),
+                         frame.add_id())) {
+    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_t* frame, uint64_t length) {
+  uint8_t* const data =
+      new (std::nothrow) uint8_t[static_cast<size_t>(length)];  // NOLINT
+  if (!data)
+    return false;
+
+  delete[] frame_;
+  frame_ = data;
+  length_ = length;
+
+  memcpy(frame_, frame, static_cast<size_t>(length_));
+  return true;
+}
+
+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;
+
+  delete[] additional_;
+  additional_ = data;
+  additional_length_ = length;
+  add_id_ = add_id;
+
+  memcpy(additional_, additional, static_cast<size_t>(additional_length_));
+  return true;
+}
+
+bool Frame::IsValid() const {
+  if (length_ == 0 || !frame_) {
+    return false;
+  }
+  if ((additional_length_ != 0 && !additional_) ||
+      (additional_ != NULL && additional_length_ == 0)) {
+    return false;
+  }
+  if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
+    return false;
+  }
+  if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
+    return false;
+  }
+  return true;
+}
+
+bool Frame::CanBeSimpleBlock() const {
+  return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
+}
+
+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;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// CuePoint Class
+
+CuePoint::CuePoint()
+    : time_(0),
+      track_(0),
+      cluster_pos_(0),
+      block_number_(1),
+      output_block_number_(true) {}
+
+CuePoint::~CuePoint() {}
+
+bool CuePoint::Write(IMkvWriter* writer) const {
+  if (!writer || track_ < 1 || cluster_pos_ < 1)
+    return false;
+
+  uint64_t size =
+      EbmlElementSize(libwebm::kMkvCueClusterPosition, cluster_pos_);
+  size += EbmlElementSize(libwebm::kMkvCueTrack, track_);
+  if (output_block_number_ && block_number_ > 1)
+    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, libwebm::kMkvCuePoint, payload_size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueTime, time_))
+    return false;
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvCueTrackPositions, size))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueTrack, track_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvCueClusterPosition, cluster_pos_))
+    return false;
+  if (output_block_number_ && block_number_ > 1)
+    if (!WriteEbmlElement(writer, libwebm::kMkvCueBlockNumber, block_number_))
+      return false;
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0)
+    return false;
+
+  if (stop_position - payload_position != static_cast<int64_t>(payload_size))
+    return false;
+
+  return true;
+}
+
+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(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_t CuePoint::Size() const {
+  const uint64_t payload_size = PayloadSize();
+  return EbmlMasterElementSize(libwebm::kMkvCuePoint, payload_size) +
+         payload_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Cues Class
+
+Cues::Cues()
+    : cue_entries_capacity_(0),
+      cue_entries_size_(0),
+      cue_entries_(NULL),
+      output_block_number_(true) {}
+
+Cues::~Cues() {
+  if (cue_entries_) {
+    for (int32_t i = 0; i < cue_entries_size_; ++i) {
+      CuePoint* const cue = cue_entries_[i];
+      delete cue;
+    }
+    delete[] cue_entries_;
+  }
+}
+
+bool Cues::AddCue(CuePoint* cue) {
+  if (!cue)
+    return false;
+
+  if ((cue_entries_size_ + 1) > cue_entries_capacity_) {
+    // Add more CuePoints.
+    const int32_t new_capacity =
+        (!cue_entries_capacity_) ? 2 : cue_entries_capacity_ * 2;
+
+    if (new_capacity < 1)
+      return false;
+
+    CuePoint** const cues =
+        new (std::nothrow) CuePoint*[new_capacity];  // NOLINT
+    if (!cues)
+      return false;
+
+    for (int32_t i = 0; i < cue_entries_size_; ++i) {
+      cues[i] = cue_entries_[i];
+    }
+
+    delete[] cue_entries_;
+
+    cue_entries_ = cues;
+    cue_entries_capacity_ = new_capacity;
+  }
+
+  cue->set_output_block_number(output_block_number_);
+  cue_entries_[cue_entries_size_++] = cue;
+  return true;
+}
+
+CuePoint* Cues::GetCueByIndex(int32_t index) const {
+  if (cue_entries_ == NULL)
+    return NULL;
+
+  if (index >= cue_entries_size_)
+    return NULL;
+
+  return cue_entries_[index];
+}
+
+uint64_t Cues::Size() {
+  uint64_t size = 0;
+  for (int32_t i = 0; i < cue_entries_size_; ++i)
+    size += GetCueByIndex(i)->Size();
+  size += EbmlMasterElementSize(libwebm::kMkvCues, size);
+  return size;
+}
+
+bool Cues::Write(IMkvWriter* writer) const {
+  if (!writer)
+    return false;
+
+  uint64_t size = 0;
+  for (int32_t i = 0; i < cue_entries_size_; ++i) {
+    const CuePoint* const cue = GetCueByIndex(i);
+
+    if (!cue)
+      return false;
+
+    size += cue->Size();
+  }
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvCues, size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  for (int32_t i = 0; i < cue_entries_size_; ++i) {
+    const CuePoint* const cue = GetCueByIndex(i);
+
+    if (!cue->Write(writer))
+      return false;
+  }
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0)
+    return false;
+
+  if (stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// ContentEncAESSettings Class
+
+ContentEncAESSettings::ContentEncAESSettings() : cipher_mode_(kCTR) {}
+
+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_t payload = PayloadSize();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncAESSettings,
+                              payload))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvAESSettingsCipherMode,
+                        cipher_mode_))
+    return false;
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(payload))
+    return false;
+
+  return true;
+}
+
+uint64_t ContentEncAESSettings::PayloadSize() const {
+  uint64_t size =
+      EbmlElementSize(libwebm::kMkvAESSettingsCipherMode, cipher_mode_);
+  return size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// ContentEncoding Class
+
+ContentEncoding::ContentEncoding()
+    : enc_algo_(5),
+      enc_key_id_(NULL),
+      encoding_order_(0),
+      encoding_scope_(1),
+      encoding_type_(1),
+      enc_key_id_length_(0) {}
+
+ContentEncoding::~ContentEncoding() { delete[] enc_key_id_; }
+
+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_t[static_cast<size_t>(length)];  // NOLINT
+  if (!enc_key_id_)
+    return false;
+
+  memcpy(enc_key_id_, id, static_cast<size_t>(length));
+  enc_key_id_length_ = length;
+
+  return true;
+}
+
+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_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_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncoding,
+                              encoding_size))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingOrder,
+                        encoding_order_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingScope,
+                        encoding_scope_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncodingType,
+                        encoding_type_))
+    return false;
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvContentEncryption,
+                              encryption_size))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncAlgo, enc_algo_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvContentEncKeyID, enc_key_id_,
+                        enc_key_id_length_))
+    return false;
+
+  if (!enc_aes_settings_.Write(writer))
+    return false;
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  return true;
+}
+
+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_t encoding_size = 0;
+
+  if (encryption_size > 0) {
+    encoding_size +=
+        EbmlMasterElementSize(libwebm::kMkvContentEncryption, encryption_size) +
+        encryption_size;
+  }
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingType, encoding_type_);
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingScope, encoding_scope_);
+  encoding_size +=
+      EbmlElementSize(libwebm::kMkvContentEncodingOrder, encoding_order_);
+
+  return encoding_size;
+}
+
+uint64_t ContentEncoding::EncryptionSize() const {
+  const uint64_t aes_size = enc_aes_settings_.Size();
+
+  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;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Track Class
+
+Track::Track(unsigned int* seed)
+    : codec_id_(NULL),
+      codec_private_(NULL),
+      language_(NULL),
+      max_block_additional_id_(0),
+      name_(NULL),
+      number_(0),
+      type_(0),
+      uid_(MakeUID(seed)),
+      codec_delay_(0),
+      seek_pre_roll_(0),
+      default_duration_(0),
+      codec_private_length_(0),
+      content_encoding_entries_(NULL),
+      content_encoding_entries_size_(0) {}
+
+Track::~Track() {
+  delete[] codec_id_;
+  delete[] codec_private_;
+  delete[] language_;
+  delete[] name_;
+
+  if (content_encoding_entries_) {
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+      ContentEncoding* const encoding = content_encoding_entries_[i];
+      delete encoding;
+    }
+    delete[] content_encoding_entries_;
+  }
+}
+
+bool Track::AddContentEncoding() {
+  const uint32_t count = content_encoding_entries_size_ + 1;
+
+  ContentEncoding** const content_encoding_entries =
+      new (std::nothrow) ContentEncoding*[count];  // NOLINT
+  if (!content_encoding_entries)
+    return false;
+
+  ContentEncoding* const content_encoding =
+      new (std::nothrow) ContentEncoding();  // NOLINT
+  if (!content_encoding) {
+    delete[] content_encoding_entries;
+    return false;
+  }
+
+  for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+    content_encoding_entries[i] = content_encoding_entries_[i];
+  }
+
+  delete[] content_encoding_entries_;
+
+  content_encoding_entries_ = content_encoding_entries;
+  content_encoding_entries_[content_encoding_entries_size_] = content_encoding;
+  content_encoding_entries_size_ = count;
+  return true;
+}
+
+ContentEncoding* Track::GetContentEncodingByIndex(uint32_t index) const {
+  if (content_encoding_entries_ == NULL)
+    return NULL;
+
+  if (index >= content_encoding_entries_size_)
+    return NULL;
+
+  return content_encoding_entries_[index];
+}
+
+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(libwebm::kMkvCodecID, codec_id_);
+  if (codec_private_)
+    size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
+                            codec_private_length_);
+  if (language_)
+    size += EbmlElementSize(libwebm::kMkvLanguage, language_);
+  if (name_)
+    size += EbmlElementSize(libwebm::kMkvName, name_);
+  if (max_block_additional_id_)
+    size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+                            max_block_additional_id_);
+  if (codec_delay_)
+    size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
+  if (seek_pre_roll_)
+    size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
+  if (default_duration_)
+    size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
+
+  if (content_encoding_entries_size_ > 0) {
+    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(libwebm::kMkvContentEncodings,
+                                  content_encodings_size) +
+            content_encodings_size;
+  }
+
+  return size;
+}
+
+uint64_t Track::Size() const {
+  uint64_t size = PayloadSize();
+  size += EbmlMasterElementSize(libwebm::kMkvTrackEntry, size);
+  return size;
+}
+
+bool Track::Write(IMkvWriter* writer) const {
+  if (!writer)
+    return false;
+
+  // mandatory elements without a default value.
+  if (!type_ || !codec_id_)
+    return false;
+
+  // |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_t payload_size = PayloadSize();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTrackEntry, payload_size))
+    return false;
+
+  uint64_t size = EbmlElementSize(libwebm::kMkvTrackNumber, number_);
+  size += EbmlElementSize(libwebm::kMkvTrackUID, uid_);
+  size += EbmlElementSize(libwebm::kMkvTrackType, type_);
+  if (codec_id_)
+    size += EbmlElementSize(libwebm::kMkvCodecID, codec_id_);
+  if (codec_private_)
+    size += EbmlElementSize(libwebm::kMkvCodecPrivate, codec_private_,
+                            codec_private_length_);
+  if (language_)
+    size += EbmlElementSize(libwebm::kMkvLanguage, language_);
+  if (name_)
+    size += EbmlElementSize(libwebm::kMkvName, name_);
+  if (max_block_additional_id_)
+    size += EbmlElementSize(libwebm::kMkvMaxBlockAdditionID,
+                            max_block_additional_id_);
+  if (codec_delay_)
+    size += EbmlElementSize(libwebm::kMkvCodecDelay, codec_delay_);
+  if (seek_pre_roll_)
+    size += EbmlElementSize(libwebm::kMkvSeekPreRoll, seek_pre_roll_);
+  if (default_duration_)
+    size += EbmlElementSize(libwebm::kMkvDefaultDuration, default_duration_);
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackNumber, number_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackUID, uid_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvTrackType, type_))
+    return false;
+  if (max_block_additional_id_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvMaxBlockAdditionID,
+                          max_block_additional_id_)) {
+      return false;
+    }
+  }
+  if (codec_delay_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecDelay, codec_delay_))
+      return false;
+  }
+  if (seek_pre_roll_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvSeekPreRoll, seek_pre_roll_))
+      return false;
+  }
+  if (default_duration_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvDefaultDuration,
+                          default_duration_))
+      return false;
+  }
+  if (codec_id_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecID, codec_id_))
+      return false;
+  }
+  if (codec_private_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvCodecPrivate, codec_private_,
+                          codec_private_length_))
+      return false;
+  }
+  if (language_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvLanguage, language_))
+      return false;
+  }
+  if (name_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvName, name_))
+      return false;
+  }
+
+  int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  if (content_encoding_entries_size_ > 0) {
+    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, libwebm::kMkvContentEncodings,
+                                content_encodings_size))
+      return false;
+
+    for (uint32_t i = 0; i < content_encoding_entries_size_; ++i) {
+      ContentEncoding* const encoding = content_encoding_entries_[i];
+      if (!encoding->Write(writer))
+        return false;
+    }
+  }
+
+  stop_position = writer->Position();
+  if (stop_position < 0)
+    return false;
+  return true;
+}
+
+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_t[static_cast<size_t>(length)];  // NOLINT
+  if (!codec_private_)
+    return false;
+
+  memcpy(codec_private_, codec_private, static_cast<size_t>(length));
+  codec_private_length_ = length;
+
+  return true;
+}
+
+void Track::set_codec_id(const char* codec_id) {
+  if (codec_id) {
+    delete[] codec_id_;
+
+    const size_t length = strlen(codec_id) + 1;
+    codec_id_ = new (std::nothrow) char[length];  // NOLINT
+    if (codec_id_) {
+#ifdef _MSC_VER
+      strcpy_s(codec_id_, length, codec_id);
+#else
+      strcpy(codec_id_, codec_id);
+#endif
+    }
+  }
+}
+
+// TODO(fgalligan): Vet the language parameter.
+void Track::set_language(const char* language) {
+  if (language) {
+    delete[] language_;
+
+    const size_t length = strlen(language) + 1;
+    language_ = new (std::nothrow) char[length];  // NOLINT
+    if (language_) {
+#ifdef _MSC_VER
+      strcpy_s(language_, length, language);
+#else
+      strcpy(language_, language);
+#endif
+    }
+  }
+}
+
+void Track::set_name(const char* name) {
+  if (name) {
+    delete[] name_;
+
+    const size_t length = strlen(name) + 1;
+    name_ = new (std::nothrow) char[length];  // NOLINT
+    if (name_) {
+#ifdef _MSC_VER
+      strcpy_s(name_, length, name);
+#else
+      strcpy(name_, name);
+#endif
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////
+//
+// 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
+
+VideoTrack::VideoTrack(unsigned int* seed)
+    : Track(seed),
+      display_height_(0),
+      display_width_(0),
+      crop_left_(0),
+      crop_right_(0),
+      crop_top_(0),
+      crop_bottom_(0),
+      frame_rate_(0.0),
+      height_(0),
+      stereo_mode_(0),
+      alpha_mode_(0),
+      width_(0),
+      colour_(NULL) {}
+
+VideoTrack::~VideoTrack() { delete colour_; }
+
+bool VideoTrack::SetStereoMode(uint64_t stereo_mode) {
+  if (stereo_mode != kMono && stereo_mode != kSideBySideLeftIsFirst &&
+      stereo_mode != kTopBottomRightIsFirst &&
+      stereo_mode != kTopBottomLeftIsFirst &&
+      stereo_mode != kSideBySideRightIsFirst)
+    return false;
+
+  stereo_mode_ = stereo_mode;
+  return true;
+}
+
+bool VideoTrack::SetAlphaMode(uint64_t alpha_mode) {
+  if (alpha_mode != kNoAlpha && alpha_mode != kAlpha)
+    return false;
+
+  alpha_mode_ = alpha_mode;
+  return true;
+}
+
+uint64_t VideoTrack::PayloadSize() const {
+  const uint64_t parent_size = Track::PayloadSize();
+
+  uint64_t size = VideoPayloadSize();
+  size += EbmlMasterElementSize(libwebm::kMkvVideo, size);
+
+  return parent_size + size;
+}
+
+bool VideoTrack::Write(IMkvWriter* writer) const {
+  if (!Track::Write(writer))
+    return false;
+
+  const uint64_t size = VideoPayloadSize();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvVideo, size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvPixelWidth, width_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvPixelHeight, height_))
+    return false;
+  if (display_width_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvDisplayWidth, display_width_))
+      return false;
+  }
+  if (display_height_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvDisplayHeight, display_height_))
+      return false;
+  }
+  if (crop_left_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropLeft, crop_left_))
+      return false;
+  }
+  if (crop_right_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropRight, crop_right_))
+      return false;
+  }
+  if (crop_top_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropTop, crop_top_))
+      return false;
+  }
+  if (crop_bottom_ > 0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvPixelCropBottom, crop_bottom_))
+      return false;
+  }
+  if (stereo_mode_ > kMono) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvStereoMode, stereo_mode_))
+      return false;
+  }
+  if (alpha_mode_ > kNoAlpha) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvAlphaMode, alpha_mode_))
+      return false;
+  }
+  if (frame_rate_ > 0.0) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvFrameRate,
+                          static_cast<float>(frame_rate_))) {
+      return false;
+    }
+  }
+  if (colour_) {
+    if (!colour_->Write(writer))
+      return false;
+  }
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      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_t VideoTrack::VideoPayloadSize() const {
+  uint64_t size = EbmlElementSize(libwebm::kMkvPixelWidth, width_);
+  size += EbmlElementSize(libwebm::kMkvPixelHeight, height_);
+  if (display_width_ > 0)
+    size += EbmlElementSize(libwebm::kMkvDisplayWidth, display_width_);
+  if (display_height_ > 0)
+    size += EbmlElementSize(libwebm::kMkvDisplayHeight, display_height_);
+  if (crop_left_ > 0)
+    size += EbmlElementSize(libwebm::kMkvPixelCropLeft, crop_left_);
+  if (crop_right_ > 0)
+    size += EbmlElementSize(libwebm::kMkvPixelCropRight, crop_right_);
+  if (crop_top_ > 0)
+    size += EbmlElementSize(libwebm::kMkvPixelCropTop, crop_top_);
+  if (crop_bottom_ > 0)
+    size += EbmlElementSize(libwebm::kMkvPixelCropBottom, crop_bottom_);
+  if (stereo_mode_ > kMono)
+    size += EbmlElementSize(libwebm::kMkvStereoMode, stereo_mode_);
+  if (alpha_mode_ > kNoAlpha)
+    size += EbmlElementSize(libwebm::kMkvAlphaMode, alpha_mode_);
+  if (frame_rate_ > 0.0)
+    size += EbmlElementSize(libwebm::kMkvFrameRate,
+                            static_cast<float>(frame_rate_));
+  if (colour_)
+    size += colour_->ColourSize();
+
+  return size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// AudioTrack Class
+
+AudioTrack::AudioTrack(unsigned int* seed)
+    : Track(seed), bit_depth_(0), channels_(1), sample_rate_(0.0) {}
+
+AudioTrack::~AudioTrack() {}
+
+uint64_t AudioTrack::PayloadSize() const {
+  const uint64_t parent_size = Track::PayloadSize();
+
+  uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+                                  static_cast<float>(sample_rate_));
+  size += EbmlElementSize(libwebm::kMkvChannels, channels_);
+  if (bit_depth_ > 0)
+    size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
+  size += EbmlMasterElementSize(libwebm::kMkvAudio, size);
+
+  return parent_size + size;
+}
+
+bool AudioTrack::Write(IMkvWriter* writer) const {
+  if (!Track::Write(writer))
+    return false;
+
+  // Calculate AudioSettings size.
+  uint64_t size = EbmlElementSize(libwebm::kMkvSamplingFrequency,
+                                  static_cast<float>(sample_rate_));
+  size += EbmlElementSize(libwebm::kMkvChannels, channels_);
+  if (bit_depth_ > 0)
+    size += EbmlElementSize(libwebm::kMkvBitDepth, bit_depth_);
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvAudio, size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvSamplingFrequency,
+                        static_cast<float>(sample_rate_)))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvChannels, channels_))
+    return false;
+  if (bit_depth_ > 0)
+    if (!WriteEbmlElement(writer, libwebm::kMkvBitDepth, bit_depth_))
+      return false;
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Tracks Class
+
+const char Tracks::kOpusCodecId[] = "A_OPUS";
+const char Tracks::kVorbisCodecId[] = "A_VORBIS";
+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), wrote_tracks_(false) {}
+
+Tracks::~Tracks() {
+  if (track_entries_) {
+    for (uint32_t i = 0; i < track_entries_size_; ++i) {
+      Track* const track = track_entries_[i];
+      delete track;
+    }
+    delete[] track_entries_;
+  }
+}
+
+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
+  // order to be able (to use Matroska integer representation) to
+  // serialize the block header (of which the track number is a part)
+  // for a frame using exactly 4 bytes.
+
+  if (number > 0x7E)
+    return false;
+
+  uint32_t track_num = number;
+
+  if (track_num > 0) {
+    // Check to make sure a track does not already have |track_num|.
+    for (uint32_t i = 0; i < track_entries_size_; ++i) {
+      if (track_entries_[i]->number() == track_num)
+        return false;
+    }
+  }
+
+  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_t i = 0; i < track_entries_size_; ++i) {
+    track_entries[i] = track_entries_[i];
+  }
+
+  delete[] track_entries_;
+
+  // Find the lowest availible track number > 0.
+  if (track_num == 0) {
+    track_num = count;
+
+    // Check to make sure a track does not already have |track_num|.
+    bool exit = false;
+    do {
+      exit = true;
+      for (uint32_t i = 0; i < track_entries_size_; ++i) {
+        if (track_entries[i]->number() == track_num) {
+          track_num++;
+          exit = false;
+          break;
+        }
+      }
+    } while (!exit);
+  }
+  track->set_number(track_num);
+
+  track_entries_ = track_entries;
+  track_entries_[track_entries_size_] = track;
+  track_entries_size_ = count;
+  return true;
+}
+
+const Track* Tracks::GetTrackByIndex(uint32_t index) const {
+  if (track_entries_ == NULL)
+    return NULL;
+
+  if (index >= track_entries_size_)
+    return NULL;
+
+  return track_entries_[index];
+}
+
+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];
+  }
+
+  return NULL;
+}
+
+bool Tracks::TrackIsAudio(uint64_t track_number) const {
+  const Track* const track = GetTrackByNumber(track_number);
+
+  if (track->type() == kAudio)
+    return true;
+
+  return false;
+}
+
+bool Tracks::TrackIsVideo(uint64_t track_number) const {
+  const Track* const track = GetTrackByNumber(track_number);
+
+  if (track->type() == kVideo)
+    return true;
+
+  return false;
+}
+
+bool Tracks::Write(IMkvWriter* writer) const {
+  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)
+      return false;
+
+    size += track->Size();
+  }
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTracks, size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  for (int32_t i = 0; i < count; ++i) {
+    const Track* const track = GetTrackByIndex(i);
+    if (!track->Write(writer))
+      return false;
+  }
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  wrote_tracks_ = true;
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Chapter Class
+
+bool Chapter::set_id(const char* id) { return StrCpy(id, &id_); }
+
+void Chapter::set_time(const Segment& segment, uint64_t start_ns,
+                       uint64_t end_ns) {
+  const SegmentInfo* const info = segment.GetSegmentInfo();
+  const uint64_t timecode_scale = info->timecode_scale();
+  start_timecode_ = start_ns / timecode_scale;
+  end_timecode_ = end_ns / timecode_scale;
+}
+
+bool Chapter::add_string(const char* title, const char* language,
+                         const char* country) {
+  if (!ExpandDisplaysArray())
+    return false;
+
+  Display& d = displays_[displays_count_++];
+  d.Init();
+
+  if (!d.set_title(title))
+    return false;
+
+  if (!d.set_language(language))
+    return false;
+
+  if (!d.set_country(country))
+    return false;
+
+  return true;
+}
+
+Chapter::Chapter() {
+  // This ctor only constructs the object.  Proper initialization is
+  // done in Init() (called in Chapters::AddChapter()).  The only
+  // reason we bother implementing this ctor is because we had to
+  // declare it as private (along with the dtor), in order to prevent
+  // clients from creating Chapter instances (a privelege we grant
+  // only to the Chapters class).  Doing no initialization here also
+  // means that creating arrays of chapter objects is more efficient,
+  // because we only initialize each new chapter object as it becomes
+  // active on the array.
+}
+
+Chapter::~Chapter() {}
+
+void Chapter::Init(unsigned int* seed) {
+  id_ = NULL;
+  start_timecode_ = 0;
+  end_timecode_ = 0;
+  displays_ = NULL;
+  displays_size_ = 0;
+  displays_count_ = 0;
+  uid_ = MakeUID(seed);
+}
+
+void Chapter::ShallowCopy(Chapter* dst) const {
+  dst->id_ = id_;
+  dst->start_timecode_ = start_timecode_;
+  dst->end_timecode_ = end_timecode_;
+  dst->uid_ = uid_;
+  dst->displays_ = displays_;
+  dst->displays_size_ = displays_size_;
+  dst->displays_count_ = displays_count_;
+}
+
+void Chapter::Clear() {
+  StrCpy(NULL, &id_);
+
+  while (displays_count_ > 0) {
+    Display& d = displays_[--displays_count_];
+    d.Clear();
+  }
+
+  delete[] displays_;
+  displays_ = NULL;
+
+  displays_size_ = 0;
+}
+
+bool Chapter::ExpandDisplaysArray() {
+  if (displays_size_ > displays_count_)
+    return true;  // nothing to do yet
+
+  const int size = (displays_size_ == 0) ? 1 : 2 * displays_size_;
+
+  Display* const displays = new (std::nothrow) Display[size];  // NOLINT
+  if (displays == NULL)
+    return false;
+
+  for (int idx = 0; idx < displays_count_; ++idx) {
+    displays[idx] = displays_[idx];  // shallow copy
+  }
+
+  delete[] displays_;
+
+  displays_ = displays;
+  displays_size_ = size;
+
+  return true;
+}
+
+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_t atom_size =
+      EbmlMasterElementSize(libwebm::kMkvChapterAtom, payload_size) +
+      payload_size;
+
+  if (writer == NULL)
+    return atom_size;
+
+  const int64_t start = writer->Position();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterAtom, payload_size))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterStringUID, id_))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterUID, uid_))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeStart, start_timecode_))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapterTimeEnd, end_timecode_))
+    return 0;
+
+  for (int idx = 0; idx < displays_count_; ++idx) {
+    const Display& d = displays_[idx];
+
+    if (!d.WriteDisplay(writer))
+      return 0;
+  }
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != atom_size)
+    return 0;
+
+  return atom_size;
+}
+
+void Chapter::Display::Init() {
+  title_ = NULL;
+  language_ = NULL;
+  country_ = NULL;
+}
+
+void Chapter::Display::Clear() {
+  StrCpy(NULL, &title_);
+  StrCpy(NULL, &language_);
+  StrCpy(NULL, &country_);
+}
+
+bool Chapter::Display::set_title(const char* title) {
+  return StrCpy(title, &title_);
+}
+
+bool Chapter::Display::set_language(const char* language) {
+  return StrCpy(language, &language_);
+}
+
+bool Chapter::Display::set_country(const char* country) {
+  return StrCpy(country, &country_);
+}
+
+uint64_t Chapter::Display::WriteDisplay(IMkvWriter* writer) const {
+  uint64_t payload_size = EbmlElementSize(libwebm::kMkvChapString, title_);
+
+  if (language_)
+    payload_size += EbmlElementSize(libwebm::kMkvChapLanguage, language_);
+
+  if (country_)
+    payload_size += EbmlElementSize(libwebm::kMkvChapCountry, country_);
+
+  const uint64_t display_size =
+      EbmlMasterElementSize(libwebm::kMkvChapterDisplay, payload_size) +
+      payload_size;
+
+  if (writer == NULL)
+    return display_size;
+
+  const int64_t start = writer->Position();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapterDisplay,
+                              payload_size))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvChapString, title_))
+    return 0;
+
+  if (language_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvChapLanguage, language_))
+      return 0;
+  }
+
+  if (country_) {
+    if (!WriteEbmlElement(writer, libwebm::kMkvChapCountry, country_))
+      return 0;
+  }
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != display_size)
+    return 0;
+
+  return display_size;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Chapters Class
+
+Chapters::Chapters() : chapters_size_(0), chapters_count_(0), chapters_(NULL) {}
+
+Chapters::~Chapters() {
+  while (chapters_count_ > 0) {
+    Chapter& chapter = chapters_[--chapters_count_];
+    chapter.Clear();
+  }
+
+  delete[] chapters_;
+  chapters_ = NULL;
+}
+
+int Chapters::Count() const { return chapters_count_; }
+
+Chapter* Chapters::AddChapter(unsigned int* seed) {
+  if (!ExpandChaptersArray())
+    return NULL;
+
+  Chapter& chapter = chapters_[chapters_count_++];
+  chapter.Init(seed);
+
+  return &chapter;
+}
+
+bool Chapters::Write(IMkvWriter* writer) const {
+  if (writer == NULL)
+    return false;
+
+  const uint64_t payload_size = WriteEdition(NULL);  // return size only
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvChapters, payload_size))
+    return false;
+
+  const int64_t start = writer->Position();
+
+  if (WriteEdition(writer) == 0)  // error
+    return false;
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != payload_size)
+    return false;
+
+  return true;
+}
+
+bool Chapters::ExpandChaptersArray() {
+  if (chapters_size_ > chapters_count_)
+    return true;  // nothing to do yet
+
+  const int size = (chapters_size_ == 0) ? 1 : 2 * chapters_size_;
+
+  Chapter* const chapters = new (std::nothrow) Chapter[size];  // NOLINT
+  if (chapters == NULL)
+    return false;
+
+  for (int idx = 0; idx < chapters_count_; ++idx) {
+    const Chapter& src = chapters_[idx];
+    Chapter* const dst = chapters + idx;
+    src.ShallowCopy(dst);
+  }
+
+  delete[] chapters_;
+
+  chapters_ = chapters;
+  chapters_size_ = size;
+
+  return true;
+}
+
+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_t edition_size =
+      EbmlMasterElementSize(libwebm::kMkvEditionEntry, payload_size) +
+      payload_size;
+
+  if (writer == NULL)  // return size only
+    return edition_size;
+
+  const int64_t start = writer->Position();
+
+  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_t chapter_size = chapter.WriteAtom(writer);
+    if (chapter_size == 0)  // error
+      return 0;
+  }
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != edition_size)
+    return 0;
+
+  return edition_size;
+}
+
+// Tag Class
+
+bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
+  if (!ExpandSimpleTagsArray())
+    return false;
+
+  SimpleTag& st = simple_tags_[simple_tags_count_++];
+  st.Init();
+
+  if (!st.set_tag_name(tag_name))
+    return false;
+
+  if (!st.set_tag_string(tag_string))
+    return false;
+
+  return true;
+}
+
+Tag::Tag() {
+  simple_tags_ = NULL;
+  simple_tags_size_ = 0;
+  simple_tags_count_ = 0;
+}
+
+Tag::~Tag() {}
+
+void Tag::ShallowCopy(Tag* dst) const {
+  dst->simple_tags_ = simple_tags_;
+  dst->simple_tags_size_ = simple_tags_size_;
+  dst->simple_tags_count_ = simple_tags_count_;
+}
+
+void Tag::Clear() {
+  while (simple_tags_count_ > 0) {
+    SimpleTag& st = simple_tags_[--simple_tags_count_];
+    st.Clear();
+  }
+
+  delete[] simple_tags_;
+  simple_tags_ = NULL;
+
+  simple_tags_size_ = 0;
+}
+
+bool Tag::ExpandSimpleTagsArray() {
+  if (simple_tags_size_ > simple_tags_count_)
+    return true;  // nothing to do yet
+
+  const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
+
+  SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size];  // NOLINT
+  if (simple_tags == NULL)
+    return false;
+
+  for (int idx = 0; idx < simple_tags_count_; ++idx) {
+    simple_tags[idx] = simple_tags_[idx];  // shallow copy
+  }
+
+  delete[] simple_tags_;
+
+  simple_tags_ = simple_tags;
+  simple_tags_size_ = size;
+
+  return true;
+}
+
+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_t tag_size =
+      EbmlMasterElementSize(libwebm::kMkvTag, payload_size) + payload_size;
+
+  if (writer == NULL)
+    return tag_size;
+
+  const int64_t start = writer->Position();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvTag, payload_size))
+    return 0;
+
+  for (int idx = 0; idx < simple_tags_count_; ++idx) {
+    const SimpleTag& st = simple_tags_[idx];
+
+    if (!st.Write(writer))
+      return 0;
+  }
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != tag_size)
+    return 0;
+
+  return tag_size;
+}
+
+// Tag::SimpleTag
+
+void Tag::SimpleTag::Init() {
+  tag_name_ = NULL;
+  tag_string_ = NULL;
+}
+
+void Tag::SimpleTag::Clear() {
+  StrCpy(NULL, &tag_name_);
+  StrCpy(NULL, &tag_string_);
+}
+
+bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
+  return StrCpy(tag_name, &tag_name_);
+}
+
+bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
+  return StrCpy(tag_string, &tag_string_);
+}
+
+uint64_t Tag::SimpleTag::Write(IMkvWriter* writer) const {
+  uint64_t payload_size = EbmlElementSize(libwebm::kMkvTagName, tag_name_);
+
+  payload_size += EbmlElementSize(libwebm::kMkvTagString, tag_string_);
+
+  const uint64_t simple_tag_size =
+      EbmlMasterElementSize(libwebm::kMkvSimpleTag, payload_size) +
+      payload_size;
+
+  if (writer == NULL)
+    return simple_tag_size;
+
+  const int64_t start = writer->Position();
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvSimpleTag, payload_size))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvTagName, tag_name_))
+    return 0;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvTagString, tag_string_))
+    return 0;
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != simple_tag_size)
+    return 0;
+
+  return simple_tag_size;
+}
+
+// Tags Class
+
+Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
+
+Tags::~Tags() {
+  while (tags_count_ > 0) {
+    Tag& tag = tags_[--tags_count_];
+    tag.Clear();
+  }
+
+  delete[] tags_;
+  tags_ = NULL;
+}
+
+int Tags::Count() const { return tags_count_; }
+
+Tag* Tags::AddTag() {
+  if (!ExpandTagsArray())
+    return NULL;
+
+  Tag& tag = tags_[tags_count_++];
+
+  return &tag;
+}
+
+bool Tags::Write(IMkvWriter* writer) const {
+  if (writer == NULL)
+    return false;
+
+  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, libwebm::kMkvTags, payload_size))
+    return false;
+
+  const int64_t start = writer->Position();
+
+  for (int idx = 0; idx < tags_count_; ++idx) {
+    const Tag& tag = tags_[idx];
+
+    const uint64_t tag_size = tag.Write(writer);
+    if (tag_size == 0)  // error
+      return 0;
+  }
+
+  const int64_t stop = writer->Position();
+
+  if (stop >= start && uint64_t(stop - start) != payload_size)
+    return false;
+
+  return true;
+}
+
+bool Tags::ExpandTagsArray() {
+  if (tags_size_ > tags_count_)
+    return true;  // nothing to do yet
+
+  const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
+
+  Tag* const tags = new (std::nothrow) Tag[size];  // NOLINT
+  if (tags == NULL)
+    return false;
+
+  for (int idx = 0; idx < tags_count_; ++idx) {
+    const Tag& src = tags_[idx];
+    Tag* const dst = tags + idx;
+    src.ShallowCopy(dst);
+  }
+
+  delete[] tags_;
+
+  tags_ = tags;
+  tags_size_ = size;
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Cluster class
+
+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() {}
+
+bool Cluster::Init(IMkvWriter* ptr_writer) {
+  if (!ptr_writer) {
+    return false;
+  }
+  writer_ = ptr_writer;
+  return true;
+}
+
+bool Cluster::AddFrame(const Frame* const frame) {
+  return QueueOrWriteFrame(frame);
+}
+
+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 QueueOrWriteFrame(&frame);
+}
+
+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;
+  }
+  Frame frame;
+  if (!frame.Init(data, length) ||
+      !frame.AddAdditionalData(additional, additional_length, add_id)) {
+    return false;
+  }
+  frame.set_track_number(track_number);
+  frame.set_timestamp(abs_timecode);
+  frame.set_is_key(is_key);
+  return QueueOrWriteFrame(&frame);
+}
+
+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;
+  frame.set_discard_padding(discard_padding);
+  frame.set_track_number(track_number);
+  frame.set_timestamp(abs_timecode);
+  frame.set_is_key(is_key);
+  return QueueOrWriteFrame(&frame);
+}
+
+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;
+  frame.set_track_number(track_number);
+  frame.set_timestamp(abs_timecode);
+  frame.set_duration(duration_timecode);
+  frame.set_is_key(true);  // All metadata blocks are keyframes.
+  return QueueOrWriteFrame(&frame);
+}
+
+void Cluster::AddPayloadSize(uint64_t size) { payload_size_ += size; }
+
+bool Cluster::Finalize() {
+  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_t pos = writer_->Position();
+
+    if (writer_->Position(size_position_))
+      return false;
+
+    if (WriteUIntSize(writer_, payload_size(), 8))
+      return false;
+
+    if (writer_->Position(pos))
+      return false;
+  }
+
+  finalized_ = true;
+
+  return true;
+}
+
+uint64_t Cluster::Size() const {
+  const uint64_t element_size =
+      EbmlMasterElementSize(libwebm::kMkvCluster, 0xFFFFFFFFFFFFFFFFULL) +
+      payload_size_;
+  return element_size;
+}
+
+bool Cluster::PreWriteBlock() {
+  if (finalized_)
+    return false;
+
+  if (!header_written_) {
+    if (!WriteClusterHeader())
+      return false;
+  }
+
+  return true;
+}
+
+void Cluster::PostWriteBlock(uint64_t element_size) {
+  AddPayloadSize(element_size);
+  ++blocks_added_;
+}
+
+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;
+
+  return rel_timecode;
+}
+
+bool Cluster::DoWriteFrame(const Frame* const frame) {
+  if (!frame || !frame->IsValid())
+    return false;
+
+  if (!PreWriteBlock())
+    return false;
+
+  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;
+}
+
+bool Cluster::WriteClusterHeader() {
+  if (finalized_)
+    return false;
+
+  if (WriteID(writer_, libwebm::kMkvCluster))
+    return false;
+
+  // Save for later.
+  size_position_ = writer_->Position();
+
+  // Write "unknown" (EBML coded -1) as cluster size value. We need to write 8
+  // bytes because we do not know how big our cluster will be.
+  if (SerializeInt(writer_, kEbmlUnknownValue, 8))
+    return false;
+
+  if (!WriteEbmlElement(writer_, libwebm::kMkvTimecode, timecode(),
+                        fixed_size_timecode_ ? 8 : 0)) {
+    return false;
+  }
+  AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode(),
+                                 fixed_size_timecode_ ? 8 : 0));
+  header_written_ = true;
+
+  return true;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// SeekHead Class
+
+SeekHead::SeekHead() : start_pos_(0ULL) {
+  for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+    seek_entry_id_[i] = 0;
+    seek_entry_pos_[i] = 0;
+  }
+}
+
+SeekHead::~SeekHead() {}
+
+bool SeekHead::Finalize(IMkvWriter* writer) const {
+  if (writer->Seekable()) {
+    if (start_pos_ == -1)
+      return false;
+
+    uint64_t payload_size = 0;
+    uint64_t entry_size[kSeekEntryCount];
+
+    for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+      if (seek_entry_id_[i] != 0) {
+        entry_size[i] = EbmlElementSize(
+            libwebm::kMkvSeekID, static_cast<uint64_t>(seek_entry_id_[i]));
+        entry_size[i] +=
+            EbmlElementSize(libwebm::kMkvSeekPosition, seek_entry_pos_[i]);
+
+        payload_size +=
+            EbmlMasterElementSize(libwebm::kMkvSeek, entry_size[i]) +
+            entry_size[i];
+      }
+    }
+
+    // No SeekHead elements
+    if (payload_size == 0)
+      return true;
+
+    const int64_t pos = writer->Position();
+    if (writer->Position(start_pos_))
+      return false;
+
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeekHead, payload_size))
+      return false;
+
+    for (int32_t i = 0; i < kSeekEntryCount; ++i) {
+      if (seek_entry_id_[i] != 0) {
+        if (!WriteEbmlMasterElement(writer, libwebm::kMkvSeek, entry_size[i]))
+          return false;
+
+        if (!WriteEbmlElement(writer, libwebm::kMkvSeekID,
+                              static_cast<uint64_t>(seek_entry_id_[i])))
+          return false;
+
+        if (!WriteEbmlElement(writer, libwebm::kMkvSeekPosition,
+                              seek_entry_pos_[i]))
+          return false;
+      }
+    }
+
+    const uint64_t total_entry_size = kSeekEntryCount * MaxEntrySize();
+    const uint64_t total_size =
+        EbmlMasterElementSize(libwebm::kMkvSeekHead, total_entry_size) +
+        total_entry_size;
+    const int64_t size_left = total_size - (writer->Position() - start_pos_);
+
+    const uint64_t bytes_written = WriteVoidElement(writer, size_left);
+    if (!bytes_written)
+      return false;
+
+    if (writer->Position(pos))
+      return false;
+  }
+
+  return true;
+}
+
+bool SeekHead::Write(IMkvWriter* writer) {
+  const uint64_t entry_size = kSeekEntryCount * MaxEntrySize();
+  const uint64_t size =
+      EbmlMasterElementSize(libwebm::kMkvSeekHead, entry_size);
+
+  start_pos_ = writer->Position();
+
+  const uint64_t bytes_written = WriteVoidElement(writer, size + entry_size);
+  if (!bytes_written)
+    return false;
+
+  return true;
+}
+
+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;
+      return true;
+    }
+  }
+  return false;
+}
+
+uint32_t SeekHead::GetId(int index) const {
+  if (index < 0 || index >= kSeekEntryCount)
+    return UINT_MAX;
+  return seek_entry_id_[index];
+}
+
+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_t id, uint64_t position) {
+  if (index < 0 || index >= kSeekEntryCount)
+    return false;
+  seek_entry_id_[index] = id;
+  seek_entry_pos_[index] = position;
+  return true;
+}
+
+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;
+}
+
+///////////////////////////////////////////////////////////////
+//
+// SegmentInfo Class
+
+SegmentInfo::SegmentInfo()
+    : duration_(-1.0),
+      muxing_app_(NULL),
+      timecode_scale_(1000000ULL),
+      writing_app_(NULL),
+      date_utc_(LLONG_MIN),
+      duration_pos_(-1) {}
+
+SegmentInfo::~SegmentInfo() {
+  delete[] muxing_app_;
+  delete[] writing_app_;
+}
+
+bool SegmentInfo::Init() {
+  int32_t major;
+  int32_t minor;
+  int32_t build;
+  int32_t revision;
+  GetVersion(&major, &minor, &build, &revision);
+  char temp[256];
+#ifdef _MSC_VER
+  sprintf_s(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
+            minor, build, revision);
+#else
+  snprintf(temp, sizeof(temp) / sizeof(temp[0]), "libwebm-%d.%d.%d.%d", major,
+           minor, build, revision);
+#endif
+
+  const size_t app_len = strlen(temp) + 1;
+
+  delete[] muxing_app_;
+
+  muxing_app_ = new (std::nothrow) char[app_len];  // NOLINT
+  if (!muxing_app_)
+    return false;
+
+#ifdef _MSC_VER
+  strcpy_s(muxing_app_, app_len, temp);
+#else
+  strcpy(muxing_app_, temp);
+#endif
+
+  set_writing_app(temp);
+  if (!writing_app_)
+    return false;
+  return true;
+}
+
+bool SegmentInfo::Finalize(IMkvWriter* writer) const {
+  if (!writer)
+    return false;
+
+  if (duration_ > 0.0) {
+    if (writer->Seekable()) {
+      if (duration_pos_ == -1)
+        return false;
+
+      const int64_t pos = writer->Position();
+
+      if (writer->Position(duration_pos_))
+        return false;
+
+      if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
+                            static_cast<float>(duration_)))
+        return false;
+
+      if (writer->Position(pos))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+bool SegmentInfo::Write(IMkvWriter* writer) {
+  if (!writer || !muxing_app_ || !writing_app_)
+    return false;
+
+  uint64_t size = EbmlElementSize(libwebm::kMkvTimecodeScale, timecode_scale_);
+  if (duration_ > 0.0)
+    size +=
+        EbmlElementSize(libwebm::kMkvDuration, static_cast<float>(duration_));
+  if (date_utc_ != LLONG_MIN)
+    size += EbmlDateElementSize(libwebm::kMkvDateUTC);
+  size += EbmlElementSize(libwebm::kMkvMuxingApp, muxing_app_);
+  size += EbmlElementSize(libwebm::kMkvWritingApp, writing_app_);
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvInfo, size))
+    return false;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return false;
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvTimecodeScale, timecode_scale_))
+    return false;
+
+  if (duration_ > 0.0) {
+    // Save for later
+    duration_pos_ = writer->Position();
+
+    if (!WriteEbmlElement(writer, libwebm::kMkvDuration,
+                          static_cast<float>(duration_)))
+      return false;
+  }
+
+  if (date_utc_ != LLONG_MIN)
+    WriteEbmlDateElement(writer, libwebm::kMkvDateUTC, date_utc_);
+
+  if (!WriteEbmlElement(writer, libwebm::kMkvMuxingApp, muxing_app_))
+    return false;
+  if (!WriteEbmlElement(writer, libwebm::kMkvWritingApp, writing_app_))
+    return false;
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(size))
+    return false;
+
+  return true;
+}
+
+void SegmentInfo::set_muxing_app(const char* app) {
+  if (app) {
+    const size_t length = strlen(app) + 1;
+    char* temp_str = new (std::nothrow) char[length];  // NOLINT
+    if (!temp_str)
+      return;
+
+#ifdef _MSC_VER
+    strcpy_s(temp_str, length, app);
+#else
+    strcpy(temp_str, app);
+#endif
+
+    delete[] muxing_app_;
+    muxing_app_ = temp_str;
+  }
+}
+
+void SegmentInfo::set_writing_app(const char* app) {
+  if (app) {
+    const size_t length = strlen(app) + 1;
+    char* temp_str = new (std::nothrow) char[length];  // NOLINT
+    if (!temp_str)
+      return;
+
+#ifdef _MSC_VER
+    strcpy_s(temp_str, length, app);
+#else
+    strcpy(temp_str, app);
+#endif
+
+    delete[] writing_app_;
+    writing_app_ = temp_str;
+  }
+}
+
+///////////////////////////////////////////////////////////////
+//
+// Segment Class
+
+Segment::Segment()
+    : chunk_count_(0),
+      chunk_name_(NULL),
+      chunk_writer_cluster_(NULL),
+      chunk_writer_cues_(NULL),
+      chunk_writer_header_(NULL),
+      chunking_(false),
+      chunking_base_name_(NULL),
+      cluster_list_(NULL),
+      cluster_list_capacity_(0),
+      cluster_list_size_(0),
+      cues_position_(kAfterClusters),
+      cues_track_(0),
+      force_new_cluster_(false),
+      frames_(NULL),
+      frames_capacity_(0),
+      frames_size_(0),
+      has_video_(false),
+      header_written_(false),
+      last_block_duration_(0),
+      last_timestamp_(0),
+      max_cluster_duration_(kDefaultMaxClusterDuration),
+      max_cluster_size_(0),
+      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),
+      doc_type_version_written_(0),
+      writer_cluster_(NULL),
+      writer_cues_(NULL),
+      writer_header_(NULL) {
+  const time_t curr_time = time(NULL);
+  seed_ = static_cast<unsigned int>(curr_time);
+#ifdef _WIN32
+  srand(seed_);
+#endif
+}
+
+Segment::~Segment() {
+  if (cluster_list_) {
+    for (int32_t i = 0; i < cluster_list_size_; ++i) {
+      Cluster* const cluster = cluster_list_[i];
+      delete cluster;
+    }
+    delete[] cluster_list_;
+  }
+
+  if (frames_) {
+    for (int32_t i = 0; i < frames_size_; ++i) {
+      Frame* const frame = frames_[i];
+      delete frame;
+    }
+    delete[] frames_;
+  }
+
+  delete[] chunk_name_;
+  delete[] chunking_base_name_;
+
+  if (chunk_writer_cluster_) {
+    chunk_writer_cluster_->Close();
+    delete chunk_writer_cluster_;
+  }
+  if (chunk_writer_cues_) {
+    chunk_writer_cues_->Close();
+    delete chunk_writer_cues_;
+  }
+  if (chunk_writer_header_) {
+    chunk_writer_header_->Close();
+    delete chunk_writer_header_;
+  }
+}
+
+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_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
+  //    Let b = Increase in Cue Point's size due to this iteration
+  //    Let c = Increase in size of Cues Element's length due to this iteration
+  //            (This is computed as CodedSize(a + b) - CodedSize(a))
+  //    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_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_t i = 0; i < cues_.cue_entries_size(); ++i) {
+      MoveCuesBeforeClustersHelper(diff, i, cues_size);
+    }
+  }
+}
+
+void Segment::MoveCuesBeforeClusters() {
+  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_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_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) == libwebm::kMkvCues)
+      cues_index = i;
+  }
+  seek_head_.SetSeekEntry(cues_index, libwebm::kMkvCues,
+                          seek_head_.GetPosition(cluster_index));
+  seek_head_.SetSeekEntry(cluster_index, libwebm::kMkvCluster,
+                          cues_.Size() + seek_head_.GetPosition(cues_index));
+}
+
+bool Segment::Init(IMkvWriter* ptr_writer) {
+  if (!ptr_writer) {
+    return false;
+  }
+  writer_cluster_ = ptr_writer;
+  writer_cues_ = ptr_writer;
+  writer_header_ = ptr_writer;
+  return segment_info_.Init();
+}
+
+bool Segment::CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
+                                            IMkvWriter* writer) {
+  if (!writer->Seekable() || chunking_)
+    return false;
+  const int64_t cluster_offset =
+      cluster_list_[0]->size_position() - GetUIntSize(libwebm::kMkvCluster);
+
+  // Copy the headers.
+  if (!ChunkedCopy(reader, writer, 0, cluster_offset))
+    return false;
+
+  // Recompute cue positions and seek entries.
+  MoveCuesBeforeClusters();
+
+  // Write cues and seek entries.
+  // TODO(vigneshv): As of now, it's safe to call seek_head_.Finalize() for the
+  // second time with a different writer object. But the name Finalize() doesn't
+  // indicate something we want to call more than once. So consider renaming it
+  // to write() or some such.
+  if (!cues_.Write(writer) || !seek_head_.Finalize(writer))
+    return false;
+
+  // Copy the Clusters.
+  if (!ChunkedCopy(reader, writer, cluster_offset,
+                   cluster_end_offset_ - cluster_offset))
+    return false;
+
+  // Update the Segment size in case the Cues size has changed.
+  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;
+  return true;
+}
+
+bool Segment::Finalize() {
+  if (WriteFramesAll() < 0)
+    return false;
+
+  if (cluster_list_size_ > 0) {
+    // Update last cluster's size
+    Cluster* const old_cluster = cluster_list_[cluster_list_size_ - 1];
+
+    // 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_++;
+    }
+
+    const double duration =
+        (static_cast<double>(last_timestamp_) + last_block_duration_) /
+        segment_info_.timecode_scale();
+    segment_info_.set_duration(duration);
+    if (!segment_info_.Finalize(writer_header_))
+      return false;
+
+    if (output_cues_)
+      if (!seek_head_.AddSeekEntry(libwebm::kMkvCues, MaxOffset()))
+        return false;
+
+    if (chunking_) {
+      if (!chunk_writer_cues_)
+        return false;
+
+      char* name = NULL;
+      if (!UpdateChunkName("cues", &name))
+        return false;
+
+      const bool cues_open = chunk_writer_cues_->Open(name);
+      delete[] name;
+      if (!cues_open)
+        return false;
+    }
+
+    cluster_end_offset_ = writer_cluster_->Position();
+
+    // Write the seek headers and cues
+    if (output_cues_)
+      if (!cues_.Write(writer_cues_))
+        return false;
+
+    if (!seek_head_.Finalize(writer_header_))
+      return false;
+
+    if (writer_header_->Seekable()) {
+      if (size_position_ == -1)
+        return false;
+
+      const int64_t segment_size = MaxOffset();
+      if (segment_size < 1)
+        return false;
+
+      const int64_t pos = writer_header_->Position();
+      UpdateDocTypeVersion();
+      if (doc_type_version_ != doc_type_version_written_) {
+        if (writer_header_->Position(0))
+          return false;
+
+        if (!WriteEbmlHeader(writer_header_, doc_type_version_))
+          return false;
+        if (writer_header_->Position() != ebml_header_size_)
+          return false;
+
+        doc_type_version_written_ = doc_type_version_;
+      }
+
+      if (writer_header_->Position(size_position_))
+        return false;
+
+      if (WriteUIntSize(writer_header_, segment_size, 8))
+        return false;
+
+      if (writer_header_->Position(pos))
+        return false;
+    }
+
+    if (chunking_) {
+      // Do not close any writers until the segment size has been written,
+      // otherwise the size may be off.
+      if (!chunk_writer_cues_ || !chunk_writer_header_)
+        return false;
+
+      chunk_writer_cues_->Close();
+      chunk_writer_header_->Close();
+    }
+  }
+
+  return true;
+}
+
+Track* Segment::AddTrack(int32_t number) {
+  Track* const track = new (std::nothrow) Track(&seed_);  // NOLINT
+
+  if (!track)
+    return NULL;
+
+  if (!tracks_.AddTrack(track, number)) {
+    delete track;
+    return NULL;
+  }
+
+  return track;
+}
+
+Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
+
+Tag* Segment::AddTag() { return tags_.AddTag(); }
+
+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;
+
+  track->set_type(Tracks::kVideo);
+  track->set_codec_id(Tracks::kVp8CodecId);
+  track->set_width(width);
+  track->set_height(height);
+
+  tracks_.AddTrack(track, number);
+  has_video_ = true;
+
+  return track->number();
+}
+
+bool Segment::AddCuePoint(uint64_t timestamp, uint64_t track) {
+  if (cluster_list_size_ < 1)
+    return false;
+
+  const Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+  if (!cluster)
+    return false;
+
+  CuePoint* const cue = new (std::nothrow) CuePoint();  // NOLINT
+  if (!cue)
+    return false;
+
+  cue->set_time(timestamp / segment_info_.timecode_scale());
+  cue->set_block_number(cluster->blocks_added());
+  cue->set_cluster_pos(cluster->position_for_cues());
+  cue->set_track(track);
+  if (!cues_.AddCue(cue))
+    return false;
+
+  new_cuepoint_ = false;
+  return true;
+}
+
+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;
+
+  track->set_type(Tracks::kAudio);
+  track->set_codec_id(Tracks::kVorbisCodecId);
+  track->set_sample_rate(sample_rate);
+  track->set_channels(channels);
+
+  tracks_.AddTrack(track, number);
+
+  return track->number();
+}
+
+bool Segment::AddFrame(const uint8_t* data, uint64_t length,
+                       uint64_t track_number, uint64_t timestamp, bool is_key) {
+  if (!data)
+    return false;
+
+  Frame frame;
+  if (!frame.Init(data, length))
+    return false;
+  frame.set_track_number(track_number);
+  frame.set_timestamp(timestamp);
+  frame.set_is_key(is_key);
+  return AddGenericFrame(&frame);
+}
+
+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;
+
+  Frame frame;
+  if (!frame.Init(data, length) ||
+      !frame.AddAdditionalData(additional, additional_length, add_id)) {
+    return false;
+  }
+  frame.set_track_number(track_number);
+  frame.set_timestamp(timestamp);
+  frame.set_is_key(is_key);
+  return AddGenericFrame(&frame);
+}
+
+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;
+
+  Frame frame;
+  if (!frame.Init(data, length))
+    return false;
+  frame.set_discard_padding(discard_padding);
+  frame.set_track_number(track_number);
+  frame.set_timestamp(timestamp);
+  frame.set_is_key(is_key);
+  return AddGenericFrame(&frame);
+}
+
+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;
+
+  Frame frame;
+  if (!frame.Init(data, length))
+    return false;
+  frame.set_track_number(track_number);
+  frame.set_timestamp(timestamp_ns);
+  frame.set_duration(duration_ns);
+  frame.set_is_key(true);  // All metadata blocks are keyframes.
+  return AddGenericFrame(&frame);
+}
+
+bool Segment::AddGenericFrame(const Frame* frame) {
+  if (!frame)
+    return false;
+
+  if (!CheckHeaderInfo())
+    return false;
+
+  // Check for non-monotonically increasing timestamps.
+  if (frame->timestamp() < last_timestamp_)
+    return false;
+
+  // Check if the track number is valid.
+  if (!tracks_.GetTrackByNumber(frame->track_number()))
+    return false;
+
+  if (frame->discard_padding() != 0)
+    doc_type_version_ = 4;
+
+  // If the segment has a video track hold onto audio frames to make sure the
+  // audio that is associated with the start time of a video key-frame is
+  // muxed into the same cluster.
+  if (has_video_ && tracks_.TrackIsAudio(frame->track_number()) &&
+      !force_new_cluster_) {
+    Frame* const new_frame = new (std::nothrow) Frame();
+    if (!new_frame || !new_frame->CopyFrom(*frame))
+      return false;
+    return QueueFrame(new_frame);
+  }
+
+  if (!DoNewClusterProcessing(frame->track_number(), frame->timestamp(),
+                              frame->is_key())) {
+    return false;
+  }
+
+  if (cluster_list_size_ < 1)
+    return false;
+
+  Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+  if (!cluster)
+    return false;
+
+  // If the Frame is not a SimpleBlock, then set the reference_block_timestamp
+  // if it is not set already.
+  bool frame_created = false;
+  if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
+      !frame->reference_block_timestamp_set()) {
+    Frame* const new_frame = new (std::nothrow) Frame();
+    if (!new_frame->CopyFrom(*frame))
+      return false;
+    new_frame->set_reference_block_timestamp(
+        last_track_timestamp_[frame->track_number() - 1]);
+    frame = new_frame;
+    frame_created = true;
+  }
+
+  if (!cluster->AddFrame(frame))
+    return false;
+
+  if (new_cuepoint_ && cues_track_ == frame->track_number()) {
+    if (!AddCuePoint(frame->timestamp(), cues_track_))
+      return false;
+  }
+
+  last_timestamp_ = frame->timestamp();
+  last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
+  last_block_duration_ = frame->duration();
+
+  if (frame_created)
+    delete frame;
+
+  return true;
+}
+
+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;
+
+  if (chunking) {
+    if (!filename)
+      return false;
+
+    // Check if we are being set to what is already set.
+    if (chunking_ && !strcmp(filename, chunking_base_name_))
+      return true;
+
+    const size_t name_length = strlen(filename) + 1;
+    char* const temp = new (std::nothrow) char[name_length];  // NOLINT
+    if (!temp)
+      return false;
+
+#ifdef _MSC_VER
+    strcpy_s(temp, name_length, filename);
+#else
+    strcpy(temp, filename);
+#endif
+
+    delete[] chunking_base_name_;
+    chunking_base_name_ = temp;
+
+    if (!UpdateChunkName("chk", &chunk_name_))
+      return false;
+
+    if (!chunk_writer_cluster_) {
+      chunk_writer_cluster_ = new (std::nothrow) MkvWriter();  // NOLINT
+      if (!chunk_writer_cluster_)
+        return false;
+    }
+
+    if (!chunk_writer_cues_) {
+      chunk_writer_cues_ = new (std::nothrow) MkvWriter();  // NOLINT
+      if (!chunk_writer_cues_)
+        return false;
+    }
+
+    if (!chunk_writer_header_) {
+      chunk_writer_header_ = new (std::nothrow) MkvWriter();  // NOLINT
+      if (!chunk_writer_header_)
+        return false;
+    }
+
+    if (!chunk_writer_cluster_->Open(chunk_name_))
+      return false;
+
+    const size_t header_length = strlen(filename) + strlen(".hdr") + 1;
+    char* const header = new (std::nothrow) char[header_length];  // NOLINT
+    if (!header)
+      return false;
+
+#ifdef _MSC_VER
+    strcpy_s(header, header_length - strlen(".hdr"), chunking_base_name_);
+    strcat_s(header, header_length, ".hdr");
+#else
+    strcpy(header, chunking_base_name_);
+    strcat(header, ".hdr");
+#endif
+    if (!chunk_writer_header_->Open(header)) {
+      delete[] header;
+      return false;
+    }
+
+    writer_cluster_ = chunk_writer_cluster_;
+    writer_cues_ = chunk_writer_cues_;
+    writer_header_ = chunk_writer_header_;
+
+    delete[] header;
+  }
+
+  chunking_ = chunking;
+
+  return true;
+}
+
+bool Segment::CuesTrack(uint64_t track_number) {
+  const Track* const track = GetTrackByNumber(track_number);
+  if (!track)
+    return false;
+
+  cues_track_ = track_number;
+  return true;
+}
+
+void Segment::ForceNewClusterOnNextFrame() { force_new_cluster_ = true; }
+
+Track* Segment::GetTrackByNumber(uint64_t track_number) const {
+  return tracks_.GetTrackByNumber(track_number);
+}
+
+bool Segment::WriteSegmentHeader() {
+  UpdateDocTypeVersion();
+
+  // TODO(fgalligan): Support more than one segment.
+  if (!WriteEbmlHeader(writer_header_, doc_type_version_))
+    return false;
+  doc_type_version_written_ = doc_type_version_;
+  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_, libwebm::kMkvSegment))
+    return false;
+
+  // Save for later.
+  size_position_ = writer_header_->Position();
+
+  // Write "unknown" (EBML coded -1) as segment size value. We need to write 8
+  // bytes because if we are going to overwrite the segment size later we do
+  // not know how big our segment will be.
+  if (SerializeInt(writer_header_, kEbmlUnknownValue, 8))
+    return false;
+
+  payload_pos_ = writer_header_->Position();
+
+  if (mode_ == kFile && writer_header_->Seekable()) {
+    // Set the duration > 0.0 so SegmentInfo will write out the duration. When
+    // the muxer is done writing we will set the correct duration and have
+    // SegmentInfo upadte it.
+    segment_info_.set_duration(1.0);
+
+    if (!seek_head_.Write(writer_header_))
+      return false;
+  }
+
+  if (!seek_head_.AddSeekEntry(libwebm::kMkvInfo, MaxOffset()))
+    return false;
+  if (!segment_info_.Write(writer_header_))
+    return false;
+
+  if (!seek_head_.AddSeekEntry(libwebm::kMkvTracks, MaxOffset()))
+    return false;
+  if (!tracks_.Write(writer_header_))
+    return false;
+
+  if (chapters_.Count() > 0) {
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvChapters, MaxOffset()))
+      return false;
+    if (!chapters_.Write(writer_header_))
+      return false;
+  }
+
+  if (tags_.Count() > 0) {
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvTags, MaxOffset()))
+      return false;
+    if (!tags_.Write(writer_header_))
+      return false;
+  }
+
+  if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
+    if (!chunk_writer_header_)
+      return false;
+
+    chunk_writer_header_->Close();
+  }
+
+  header_written_ = true;
+
+  return true;
+}
+
+// Here we are testing whether to create a new cluster, given a frame
+// having time 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;
+
+  // If no clusters have been created yet, then create a new cluster
+  // and write this frame immediately, in the new cluster.  This path
+  // should only be followed once, the first time we attempt to write
+  // a frame.
+
+  if (cluster_list_size_ <= 0)
+    return 1;
+
+  // There exists at least one cluster. We must compare the frame to
+  // the last cluster, in order to determine whether the frame is
+  // written to the existing cluster, or that a new cluster should be
+  // created.
+
+  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_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
+  // is allowed, this muxer doesn't actually write clusters like that,
+  // so this indicates a bug somewhere in our algorithm.
+
+  if (frame_timecode < last_cluster_timecode)  // should never happen
+    return -1;
+
+  // If the frame has a timestamp significantly larger than the last
+  // cluster (in Matroska, cluster-relative timestamps are serialized
+  // 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_t delta_timecode = frame_timecode - last_cluster_timecode;
+
+  if (delta_timecode > kMaxBlockTimecode)
+    return 2;
+
+  // We decide to create a new cluster when we have a video keyframe.
+  // This will flush queued (audio) frames, and write the keyframe
+  // immediately, in the newly-created cluster.
+
+  if (is_key && tracks_.TrackIsVideo(track_number))
+    return 1;
+
+  // Create a new cluster if we have accumulated too many frames
+  // already, where "too many" is defined as "the total time of frames
+  // in the cluster exceeds a threshold".
+
+  const uint64_t delta_ns = delta_timecode * timecode_scale;
+
+  if (max_cluster_duration_ > 0 && delta_ns >= max_cluster_duration_)
+    return 1;
+
+  // This is similar to the case above, with the difference that a new
+  // cluster is created when the size of the current cluster exceeds a
+  // threshold.
+
+  const uint64_t cluster_size = last_cluster->payload_size();
+
+  if (max_cluster_size_ > 0 && cluster_size >= max_cluster_size_)
+    return 1;
+
+  // There's no need to create a new cluster, so emit this frame now.
+
+  return 0;
+}
+
+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_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_t i = 0; i < cluster_list_size_; ++i) {
+      clusters[i] = cluster_list_[i];
+    }
+
+    delete[] cluster_list_;
+
+    cluster_list_ = clusters;
+    cluster_list_capacity_ = new_capacity;
+  }
+
+  if (!WriteFramesLessThan(frame_timestamp_ns))
+    return false;
+
+  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(true, frame_timestamp_ns))
+      return false;
+  }
+
+  if (output_cues_)
+    new_cuepoint_ = true;
+
+  if (chunking_ && cluster_list_size_ > 0) {
+    chunk_writer_cluster_->Close();
+    chunk_count_++;
+
+    if (!UpdateChunkName("chk", &chunk_name_))
+      return false;
+    if (!chunk_writer_cluster_->Open(chunk_name_))
+      return false;
+  }
+
+  const uint64_t timecode_scale = segment_info_.timecode_scale();
+  const uint64_t frame_timecode = frame_timestamp_ns / timecode_scale;
+
+  uint64_t cluster_timecode = frame_timecode;
+
+  if (frames_size_ > 0) {
+    const Frame* const f = frames_[0];  // earliest queued frame
+    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_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;
+
+  if (!cluster->Init(writer_cluster_))
+    return false;
+
+  cluster_list_size_ = new_size;
+  return true;
+}
+
+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.
+    const int result = TestFrame(track_number, frame_timestamp_ns, is_key);
+    if (result < 0)  // error
+      return false;
+
+    // Always set force_new_cluster_ to false after TestFrame.
+    force_new_cluster_ = false;
+
+    // A non-zero result means create a new cluster.
+    if (result > 0 && !MakeNewCluster(frame_timestamp_ns))
+      return false;
+
+    // Write queued (audio) frames.
+    const int frame_count = WriteFramesAll();
+    if (frame_count < 0)  // error
+      return false;
+
+    // Write the current frame to the current cluster (if TestFrame
+    // returns 0) or to a newly created cluster (TestFrame returns 1).
+    if (result <= 1)
+      return true;
+
+    // TestFrame returned 2, which means there was a large time
+    // difference between the cluster and the frame itself.  Do the
+    // test again, comparing the frame to the new cluster.
+  }
+}
+
+bool Segment::CheckHeaderInfo() {
+  if (!header_written_) {
+    if (!WriteSegmentHeader())
+      return false;
+
+    if (!seek_head_.AddSeekEntry(libwebm::kMkvCluster, MaxOffset()))
+      return false;
+
+    if (output_cues_ && cues_track_ == 0) {
+      // Check for a video track
+      for (uint32_t i = 0; i < tracks_.track_entries_size(); ++i) {
+        const Track* const track = tracks_.GetTrackByIndex(i);
+        if (!track)
+          return false;
+
+        if (tracks_.TrackIsVideo(track->number())) {
+          cues_track_ = track->number();
+          break;
+        }
+      }
+
+      // Set first track found
+      if (cues_track_ == 0) {
+        const Track* const track = tracks_.GetTrackByIndex(0);
+        if (!track)
+          return false;
+
+        cues_track_ = track->number();
+      }
+    }
+  }
+  return true;
+}
+
+void Segment::UpdateDocTypeVersion() {
+  for (uint32_t index = 0; index < tracks_.track_entries_size(); ++index) {
+    const Track* track = tracks_.GetTrackByIndex(index);
+    if (track == NULL)
+      break;
+    if ((track->codec_delay() || track->seek_pre_roll()) &&
+        doc_type_version_ < 4) {
+      doc_type_version_ = 4;
+      break;
+    }
+  }
+}
+
+bool Segment::UpdateChunkName(const char* ext, char** name) const {
+  if (!name || !ext)
+    return false;
+
+  char ext_chk[64];
+#ifdef _MSC_VER
+  sprintf_s(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
+#else
+  snprintf(ext_chk, sizeof(ext_chk), "_%06d.%s", chunk_count_, ext);
+#endif
+
+  const size_t length = strlen(chunking_base_name_) + strlen(ext_chk) + 1;
+  char* const str = new (std::nothrow) char[length];  // NOLINT
+  if (!str)
+    return false;
+
+#ifdef _MSC_VER
+  strcpy_s(str, length - strlen(ext_chk), chunking_base_name_);
+  strcat_s(str, length, ext_chk);
+#else
+  strcpy(str, chunking_base_name_);
+  strcat(str, ext_chk);
+#endif
+
+  delete[] * name;
+  *name = str;
+
+  return true;
+}
+
+int64_t Segment::MaxOffset() {
+  if (!writer_header_)
+    return -1;
+
+  int64_t offset = writer_header_->Position() - payload_pos_;
+
+  if (chunking_) {
+    for (int32_t i = 0; i < cluster_list_size_; ++i) {
+      Cluster* const cluster = cluster_list_[i];
+      offset += cluster->Size();
+    }
+
+    if (writer_cues_)
+      offset += writer_cues_->Position();
+  }
+
+  return offset;
+}
+
+bool Segment::QueueFrame(Frame* frame) {
+  const int32_t new_size = frames_size_ + 1;
+
+  if (new_size > frames_capacity_) {
+    // Add more frames.
+    const int32_t new_capacity = (!frames_capacity_) ? 2 : frames_capacity_ * 2;
+
+    if (new_capacity < 1)
+      return false;
+
+    Frame** const frames = new (std::nothrow) Frame*[new_capacity];  // NOLINT
+    if (!frames)
+      return false;
+
+    for (int32_t i = 0; i < frames_size_; ++i) {
+      frames[i] = frames_[i];
+    }
+
+    delete[] frames_;
+    frames_ = frames;
+    frames_capacity_ = new_capacity;
+  }
+
+  frames_[frames_size_++] = frame;
+
+  return true;
+}
+
+int Segment::WriteFramesAll() {
+  if (frames_ == NULL)
+    return 0;
+
+  if (cluster_list_size_ < 1)
+    return -1;
+
+  Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+
+  if (!cluster)
+    return -1;
+
+  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.
+    if (frame->discard_padding() != 0)
+      doc_type_version_ = 4;
+    if (!cluster->AddFrame(frame))
+      return -1;
+
+    if (new_cuepoint_ && cues_track_ == frame->track_number()) {
+      if (!AddCuePoint(frame->timestamp(), cues_track_))
+        return -1;
+    }
+
+    if (frame->timestamp() > last_timestamp_) {
+      last_timestamp_ = frame->timestamp();
+      last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
+    }
+
+    delete frame;
+    frame = NULL;
+  }
+
+  const int result = frames_size_;
+  frames_size_ = 0;
+
+  return result;
+}
+
+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.
+  if (frames_size_ > 0 && cluster_list_size_ > 0) {
+    if (!frames_)
+      return false;
+
+    Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
+    if (!cluster)
+      return false;
+
+    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_t i = 1; i < frames_size_; ++i) {
+      const Frame* const frame_curr = frames_[i];
+
+      if (frame_curr->timestamp() > timestamp)
+        break;
+
+      const Frame* const frame_prev = frames_[i - 1];
+      if (frame_prev->discard_padding() != 0)
+        doc_type_version_ = 4;
+      if (!cluster->AddFrame(frame_prev))
+        return false;
+
+      if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
+        if (!AddCuePoint(frame_prev->timestamp(), cues_track_))
+          return false;
+      }
+
+      ++shift_left;
+      if (frame_prev->timestamp() > last_timestamp_) {
+        last_timestamp_ = frame_prev->timestamp();
+        last_track_timestamp_[frame_prev->track_number() - 1] =
+            frame_prev->timestamp();
+      }
+
+      delete frame_prev;
+    }
+
+    if (shift_left > 0) {
+      if (shift_left >= frames_size_)
+        return false;
+
+      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];
+      }
+
+      frames_size_ = new_frames_size;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace mkvmuxer
diff --git a/third_party/libwebm/mkvmuxer.hpp b/third_party/libwebm/mkvmuxer/mkvmuxer.h
similarity index 68%
rename from third_party/libwebm/mkvmuxer.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxer.h
index 03a002c..55ba071 100644
--- a/third_party/libwebm/mkvmuxer.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.h
@@ -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 @@
 
 // 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 @@
   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 @@
   // 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 @@
   ~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 @@
 
  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 @@
 
   // 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 @@
 
  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 @@
   ~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,45 +307,158 @@
 
   // 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 {
  public:
@@ -342,76 +471,76 @@
 
   // 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 @@
 
   // 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);
+  bool SetAlphaMode(uint64_t 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_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 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_; }
+  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 @@
 
   // 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 @@
   // 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 @@
 
   // 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 @@
     // 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 @@
   // 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 @@
   // 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 @@
     // 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 @@
   // 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 @@
   // |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 @@
   //   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 @@
   //   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 @@
   //   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 @@
   // 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. 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.
-  bool Finalize();
+  // 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_t GetRelativeTimecode(int64_t 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 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 @@
 
   // 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 @@
   // 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 @@
   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 @@
   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 @@
     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 @@
   // 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 @@
   // 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 @@
   //                 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 @@
   // 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 @@
   //   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 @@
   //   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 @@
   // 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 @@
   // 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 @@
 
   // 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 @@
   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 @@
   // 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 @@
   // 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 @@
   //  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 @@
   //        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 @@
   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 @@
   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 @@
   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 @@
   // 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 @@
   LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
 };
 
-}  // end namespace mkvmuxer
+}  // namespace mkvmuxer
 
-#endif  // MKVMUXER_HPP
+#endif  // MKVMUXER_MKVMUXER_H_
diff --git a/third_party/libwebm/mkvmuxertypes.hpp b/third_party/libwebm/mkvmuxer/mkvmuxertypes.h
similarity index 86%
rename from third_party/libwebm/mkvmuxertypes.hpp
rename to third_party/libwebm/mkvmuxer/mkvmuxertypes.h
index d0fc9fe..e5db121 100644
--- a/third_party/libwebm/mkvmuxertypes.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvmuxertypes.h
@@ -6,8 +6,17 @@
 // 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
+#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
 
 // Copied from Chromium basictypes.h
 // A macro to disallow the copy constructor and operator= functions
@@ -16,15 +25,4 @@
   TypeName(const TypeName&);                       \
   void operator=(const TypeName&)
 
-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;
-
-}  // end namespace mkvmuxer
-
-#endif  // MKVMUXERTYPES_HPP
+#endif  // MKVMUXER_MKVMUXERTYPES_HPP_
diff --git a/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
new file mode 100644
index 0000000..3562b8a
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
@@ -0,0 +1,650 @@
+// 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.
+
+#include "mkvmuxer/mkvmuxerutil.h"
+
+#ifdef __ANDROID__
+#include <fcntl.h>
+#endif
+
+#include <cassert>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <new>
+
+#include "common/webmids.h"
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvwriter.h"
+
+namespace mkvmuxer {
+
+namespace {
+
+// Date elements are always 8 octets in size.
+const int kDateElementSize = 8;
+
+uint64_t WriteBlock(IMkvWriter* writer, const Frame* const frame,
+                    int64_t timecode, uint64_t timecode_scale) {
+  uint64_t block_additional_elem_size = 0;
+  uint64_t block_addid_elem_size = 0;
+  uint64_t block_more_payload_size = 0;
+  uint64_t block_more_elem_size = 0;
+  uint64_t block_additions_payload_size = 0;
+  uint64_t block_additions_elem_size = 0;
+  if (frame->additional()) {
+    block_additional_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
+                        frame->additional_length());
+    block_addid_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockAddID, frame->add_id());
+
+    block_more_payload_size =
+        block_addid_elem_size + block_additional_elem_size;
+    block_more_elem_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(libwebm::kMkvBlockAdditions,
+                              block_additions_payload_size) +
+        block_additions_payload_size;
+  }
+
+  uint64_t discard_padding_elem_size = 0;
+  if (frame->discard_padding() != 0) {
+    discard_padding_elem_size =
+        EbmlElementSize(libwebm::kMkvDiscardPadding, frame->discard_padding());
+  }
+
+  const uint64_t reference_block_timestamp =
+      frame->reference_block_timestamp() / timecode_scale;
+  uint64_t reference_block_elem_size = 0;
+  if (!frame->is_key()) {
+    reference_block_elem_size =
+        EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
+  }
+
+  const uint64_t duration = frame->duration() / timecode_scale;
+  uint64_t block_duration_elem_size = 0;
+  if (duration > 0)
+    block_duration_elem_size =
+        EbmlElementSize(libwebm::kMkvBlockDuration, duration);
+
+  const uint64_t block_payload_size = 4 + frame->length();
+  const uint64_t block_elem_size =
+      EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
+      block_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, libwebm::kMkvBlockGroup,
+                              block_group_payload_size)) {
+    return 0;
+  }
+
+  if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
+    return 0;
+
+  if (WriteUInt(writer, frame->track_number()))
+    return 0;
+
+  if (SerializeInt(writer, timecode, 2))
+    return 0;
+
+  // For a Block, flags is always 0.
+  if (SerializeInt(writer, 0, 1))
+    return 0;
+
+  if (writer->Write(frame->frame(), static_cast<uint32_t>(frame->length())))
+    return 0;
+
+  if (frame->additional()) {
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
+                                block_additions_payload_size)) {
+      return 0;
+    }
+
+    if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
+                                block_more_payload_size))
+      return 0;
+
+    if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID, frame->add_id()))
+      return 0;
+
+    if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
+                          frame->additional(), frame->additional_length())) {
+      return 0;
+    }
+  }
+
+  if (frame->discard_padding() != 0 &&
+      !WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
+                        frame->discard_padding())) {
+    return false;
+  }
+
+  if (!frame->is_key() &&
+      !WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
+                        reference_block_timestamp)) {
+    return false;
+  }
+
+  if (duration > 0 &&
+      !WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
+    return false;
+  }
+  return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
+                               block_group_payload_size) +
+         block_group_payload_size;
+}
+
+uint64_t WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
+                          int64_t timecode) {
+  if (WriteID(writer, libwebm::kMkvSimpleBlock))
+    return 0;
+
+  const int32_t size = static_cast<int32_t>(frame->length()) + 4;
+  if (WriteUInt(writer, size))
+    return 0;
+
+  if (WriteUInt(writer, static_cast<uint64_t>(frame->track_number())))
+    return 0;
+
+  if (SerializeInt(writer, timecode, 2))
+    return 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_t>(frame->length())))
+    return 0;
+
+  return static_cast<uint64_t>(GetUIntSize(libwebm::kMkvSimpleBlock) +
+                               GetCodedUIntSize(size) + 4 + frame->length());
+}
+
+}  // namespace
+
+int32_t GetCodedUIntSize(uint64_t value) {
+  if (value < 0x000000000000007FULL)
+    return 1;
+  else if (value < 0x0000000000003FFFULL)
+    return 2;
+  else if (value < 0x00000000001FFFFFULL)
+    return 3;
+  else if (value < 0x000000000FFFFFFFULL)
+    return 4;
+  else if (value < 0x00000007FFFFFFFFULL)
+    return 5;
+  else if (value < 0x000003FFFFFFFFFFULL)
+    return 6;
+  else if (value < 0x0001FFFFFFFFFFFFULL)
+    return 7;
+  return 8;
+}
+
+int32_t GetUIntSize(uint64_t value) {
+  if (value < 0x0000000000000100ULL)
+    return 1;
+  else if (value < 0x0000000000010000ULL)
+    return 2;
+  else if (value < 0x0000000001000000ULL)
+    return 3;
+  else if (value < 0x0000000100000000ULL)
+    return 4;
+  else if (value < 0x0000010000000000ULL)
+    return 5;
+  else if (value < 0x0001000000000000ULL)
+    return 6;
+  else if (value < 0x0100000000000000ULL)
+    return 7;
+  return 8;
+}
+
+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_t v = (value < 0) ? value ^ -1LL : value;
+  return GetUIntSize(2 * v);
+}
+
+uint64_t EbmlMasterElementSize(uint64_t type, uint64_t value) {
+  // Size of EBML ID
+  int32_t ebml_size = GetUIntSize(type);
+
+  // Datasize
+  ebml_size += GetCodedUIntSize(value);
+
+  return static_cast<uint64_t>(ebml_size);
+}
+
+uint64_t EbmlElementSize(uint64_t type, int64_t value) {
+  // Size of EBML ID
+  int32_t ebml_size = GetUIntSize(type);
+
+  // Datasize
+  ebml_size += GetIntSize(value);
+
+  // Size of Datasize
+  ebml_size++;
+
+  return static_cast<uint64_t>(ebml_size);
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
+  return EbmlElementSize(type, value, 0);
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value, uint64_t fixed_size) {
+  // Size of EBML ID
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+  // Datasize
+  ebml_size +=
+      (fixed_size > 0) ? fixed_size : static_cast<uint64_t>(GetUIntSize(value));
+
+  // Size of Datasize
+  ebml_size++;
+
+  return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, float /* value */) {
+  // Size of EBML ID
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+  // Datasize
+  ebml_size += sizeof(float);
+
+  // Size of Datasize
+  ebml_size++;
+
+  return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, const char* value) {
+  if (!value)
+    return 0;
+
+  // Size of EBML ID
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+  // Datasize
+  ebml_size += strlen(value);
+
+  // Size of Datasize
+  ebml_size++;
+
+  return ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, const uint8_t* value, uint64_t size) {
+  if (!value)
+    return 0;
+
+  // Size of EBML ID
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+  // Datasize
+  ebml_size += size;
+
+  // Size of Datasize
+  ebml_size += GetCodedUIntSize(size);
+
+  return ebml_size;
+}
+
+uint64_t EbmlDateElementSize(uint64_t type) {
+  // Size of EBML ID
+  uint64_t ebml_size = static_cast<uint64_t>(GetUIntSize(type));
+
+  // Datasize
+  ebml_size += kDateElementSize;
+
+  // Size of Datasize
+  ebml_size++;
+
+  return ebml_size;
+}
+
+int32_t SerializeInt(IMkvWriter* writer, int64_t value, int32_t size) {
+  if (!writer || size < 1 || size > 8)
+    return -1;
+
+  for (int32_t i = 1; i <= size; ++i) {
+    const int32_t byte_count = size - i;
+    const int32_t bit_count = byte_count * 8;
+
+    const int64_t bb = value >> bit_count;
+    const uint8_t b = static_cast<uint8_t>(bb);
+
+    const int32_t status = writer->Write(&b, 1);
+
+    if (status < 0)
+      return status;
+  }
+
+  return 0;
+}
+
+int32_t SerializeFloat(IMkvWriter* writer, float f) {
+  if (!writer)
+    return -1;
+
+  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_t u32;
+    float f;
+  } value;
+  value.f = f;
+
+  for (int32_t i = 1; i <= 4; ++i) {
+    const int32_t byte_count = 4 - i;
+    const int32_t bit_count = byte_count * 8;
+
+    const uint8_t byte = static_cast<uint8_t>(value.u32 >> bit_count);
+
+    const int32_t status = writer->Write(&byte, 1);
+
+    if (status < 0)
+      return status;
+  }
+
+  return 0;
+}
+
+int32_t WriteUInt(IMkvWriter* writer, uint64_t value) {
+  if (!writer)
+    return -1;
+
+  int32_t size = GetCodedUIntSize(value);
+
+  return WriteUIntSize(writer, value, 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_t bit = 1LL << (size * 7);
+
+    if (value > (bit - 2))
+      return -1;
+
+    value |= bit;
+  } else {
+    size = 1;
+    int64_t bit;
+
+    for (;;) {
+      bit = 1LL << (size * 7);
+      const uint64_t max = bit - 2;
+
+      if (value <= max)
+        break;
+
+      ++size;
+    }
+
+    if (size > 8)
+      return false;
+
+    value |= bit;
+  }
+
+  return SerializeInt(writer, value, size);
+}
+
+int32_t WriteID(IMkvWriter* writer, uint64_t type) {
+  if (!writer)
+    return -1;
+
+  writer->ElementStartNotify(type, writer->Position());
+
+  const int32_t size = GetUIntSize(type);
+
+  return SerializeInt(writer, type, size);
+}
+
+bool WriteEbmlMasterElement(IMkvWriter* writer, uint64_t type, uint64_t size) {
+  if (!writer)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  if (WriteUInt(writer, size))
+    return false;
+
+  return true;
+}
+
+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;
+
+  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_t>(size)))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, int64_t value) {
+  if (!writer)
+    return false;
+
+  if (WriteID(writer, type))
+    return 0;
+
+  const uint64_t size = GetIntSize(value);
+  if (WriteUInt(writer, size))
+    return false;
+
+  if (SerializeInt(writer, value, static_cast<int32_t>(size)))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, float value) {
+  if (!writer)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  if (WriteUInt(writer, 4))
+    return false;
+
+  if (SerializeFloat(writer, value))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const char* value) {
+  if (!writer || !value)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  const uint64_t length = strlen(value);
+  if (WriteUInt(writer, length))
+    return false;
+
+  if (writer->Write(value, static_cast<const uint32_t>(length)))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlElement(IMkvWriter* writer, uint64_t type, const uint8_t* value,
+                      uint64_t size) {
+  if (!writer || !value || size < 1)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  if (WriteUInt(writer, size))
+    return false;
+
+  if (writer->Write(value, static_cast<uint32_t>(size)))
+    return false;
+
+  return true;
+}
+
+bool WriteEbmlDateElement(IMkvWriter* writer, uint64_t type, int64_t value) {
+  if (!writer)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  if (WriteUInt(writer, kDateElementSize))
+    return false;
+
+  if (SerializeInt(writer, value, kDateElementSize))
+    return false;
+
+  return true;
+}
+
+uint64_t WriteFrame(IMkvWriter* writer, const Frame* const frame,
+                    Cluster* cluster) {
+  if (!writer || !frame || !frame->IsValid() || !cluster ||
+      !cluster->timecode_scale())
+    return 0;
+
+  //  Technically the timecode for a block can be less than the
+  //  timecode for the cluster itself (remember that block timecode
+  //  is a signed, 16-bit integer).  However, as a simplification we
+  //  only permit non-negative cluster-relative timecodes for blocks.
+  const int64_t relative_timecode = cluster->GetRelativeTimecode(
+      frame->timestamp() / cluster->timecode_scale());
+  if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
+    return 0;
+
+  return frame->CanBeSimpleBlock() ?
+             WriteSimpleBlock(writer, frame, relative_timecode) :
+             WriteBlock(writer, frame, relative_timecode,
+                        cluster->timecode_scale());
+}
+
+uint64_t WriteVoidElement(IMkvWriter* writer, uint64_t size) {
+  if (!writer)
+    return false;
+
+  // Subtract one for the void ID and the coded size.
+  uint64_t void_entry_size = size - 1 - GetCodedUIntSize(size - 1);
+  uint64_t void_size =
+      EbmlMasterElementSize(libwebm::kMkvVoid, void_entry_size) +
+      void_entry_size;
+
+  if (void_size != size)
+    return 0;
+
+  const int64_t payload_position = writer->Position();
+  if (payload_position < 0)
+    return 0;
+
+  if (WriteID(writer, libwebm::kMkvVoid))
+    return 0;
+
+  if (WriteUInt(writer, void_entry_size))
+    return 0;
+
+  const uint8_t value = 0;
+  for (int32_t i = 0; i < static_cast<int32_t>(void_entry_size); ++i) {
+    if (writer->Write(&value, 1))
+      return 0;
+  }
+
+  const int64_t stop_position = writer->Position();
+  if (stop_position < 0 ||
+      stop_position - payload_position != static_cast<int64_t>(void_size))
+    return 0;
+
+  return void_size;
+}
+
+void GetVersion(int32_t* major, int32_t* minor, int32_t* build,
+                int32_t* revision) {
+  *major = 0;
+  *minor = 2;
+  *build = 1;
+  *revision = 0;
+}
+
+uint64_t MakeUID(unsigned int* seed) {
+  uint64_t uid = 0;
+
+#ifdef __MINGW32__
+  srand(*seed);
+#endif
+
+  for (int i = 0; i < 7; ++i) {  // avoid problems with 8-byte values
+    uid <<= 8;
+
+// TODO(fgalligan): Move random number generation to platform specific code.
+#ifdef _MSC_VER
+    (void)seed;
+    const int32_t nn = rand();
+#elif __ANDROID__
+    int32_t temp_num = 1;
+    int fd = open("/dev/urandom", O_RDONLY);
+    if (fd != -1) {
+      read(fd, &temp_num, sizeof(temp_num));
+      close(fd);
+    }
+    const int32_t nn = temp_num;
+#elif defined __MINGW32__
+    const int32_t nn = rand();
+#else
+    const int32_t nn = rand_r(seed);
+#endif
+    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
index 0000000..0e21a2d
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h
@@ -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_
diff --git a/third_party/libwebm/mkvwriter.cpp b/third_party/libwebm/mkvmuxer/mkvwriter.cc
similarity index 96%
rename from third_party/libwebm/mkvwriter.cpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.cc
index 75d4350..ca48e14 100644
--- a/third_party/libwebm/mkvwriter.cpp
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.cc
@@ -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) {}
diff --git a/third_party/libwebm/mkvwriter.hpp b/third_party/libwebm/mkvmuxer/mkvwriter.h
similarity index 86%
rename from third_party/libwebm/mkvwriter.hpp
rename to third_party/libwebm/mkvmuxer/mkvwriter.h
index 684560c..4227c63 100644
--- a/third_party/libwebm/mkvwriter.hpp
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.h
@@ -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 @@
   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.cpp b/third_party/libwebm/mkvmuxerutil.cpp
deleted file mode 100644
index 27ab15d..0000000
--- a/third_party/libwebm/mkvmuxerutil.cpp
+++ /dev/null
@@ -1,629 +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.
-
-#include "mkvmuxerutil.hpp"
-
-#ifdef __ANDROID__
-#include <fcntl.h>
-#endif
-
-#include <cassert>
-#include <cmath>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#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
-
-namespace mkvmuxer {
-
-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;
-  if (frame->additional()) {
-    block_additional_elem_size = EbmlElementSize(
-        kMkvBlockAdditional, frame->additional(), frame->additional_length());
-    block_addid_elem_size = EbmlElementSize(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) +
-        block_more_payload_size;
-    block_additions_payload_size = block_more_elem_size;
-    block_additions_elem_size =
-        EbmlMasterElementSize(kMkvBlockAdditions,
-                              block_additions_payload_size) +
-        block_additions_payload_size;
-  }
-
-  uint64 discard_padding_elem_size = 0;
-  if (frame->discard_padding() != 0) {
-    discard_padding_elem_size =
-        EbmlElementSize(kMkvDiscardPadding, frame->discard_padding());
-  }
-
-  const uint64 reference_block_timestamp =
-      frame->reference_block_timestamp() / timecode_scale;
-  uint64 reference_block_elem_size = 0;
-  if (!frame->is_key()) {
-    reference_block_elem_size =
-        EbmlElementSize(kMkvReferenceBlock, reference_block_timestamp);
-  }
-
-  const uint64 duration = frame->duration() / timecode_scale;
-  uint64 block_duration_elem_size = 0;
-  if (duration > 0)
-    block_duration_elem_size = EbmlElementSize(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 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,
-                              block_group_payload_size)) {
-    return 0;
-  }
-
-  if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
-    return 0;
-
-  if (WriteUInt(writer, frame->track_number()))
-    return 0;
-
-  if (SerializeInt(writer, timecode, 2))
-    return 0;
-
-  // For a Block, flags is always 0.
-  if (SerializeInt(writer, 0, 1))
-    return 0;
-
-  if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
-    return 0;
-
-  if (frame->additional()) {
-    if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
-                                block_additions_payload_size)) {
-      return 0;
-    }
-
-    if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
-      return 0;
-
-    if (!WriteEbmlElement(writer, kMkvBlockAddID, frame->add_id()))
-      return 0;
-
-    if (!WriteEbmlElement(writer, kMkvBlockAdditional, frame->additional(),
-                          frame->additional_length())) {
-      return 0;
-    }
-  }
-
-  if (frame->discard_padding() != 0 &&
-      !WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
-    return false;
-  }
-
-  if (!frame->is_key() &&
-      !WriteEbmlElement(writer, kMkvReferenceBlock,
-                        reference_block_timestamp)) {
-    return false;
-  }
-
-  if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
-    return false;
-  }
-  return EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
-         block_group_payload_size;
-}
-
-uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
-                        int64 timecode) {
-  if (WriteID(writer, kMkvSimpleBlock))
-    return 0;
-
-  const int32 size = static_cast<int32>(frame->length()) + 4;
-  if (WriteUInt(writer, size))
-    return 0;
-
-  if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
-    return 0;
-
-  if (SerializeInt(writer, timecode, 2))
-    return 0;
-
-  uint64 flags = 0;
-  if (frame->is_key())
-    flags |= 0x80;
-
-  if (SerializeInt(writer, flags, 1))
-    return 0;
-
-  if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
-    return 0;
-
-  return GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
-         frame->length();
-}
-
-}  // namespace
-
-int32 GetCodedUIntSize(uint64 value) {
-  if (value < 0x000000000000007FULL)
-    return 1;
-  else if (value < 0x0000000000003FFFULL)
-    return 2;
-  else if (value < 0x00000000001FFFFFULL)
-    return 3;
-  else if (value < 0x000000000FFFFFFFULL)
-    return 4;
-  else if (value < 0x00000007FFFFFFFFULL)
-    return 5;
-  else if (value < 0x000003FFFFFFFFFFULL)
-    return 6;
-  else if (value < 0x0001FFFFFFFFFFFFULL)
-    return 7;
-  return 8;
-}
-
-int32 GetUIntSize(uint64 value) {
-  if (value < 0x0000000000000100ULL)
-    return 1;
-  else if (value < 0x0000000000010000ULL)
-    return 2;
-  else if (value < 0x0000000001000000ULL)
-    return 3;
-  else if (value < 0x0000000100000000ULL)
-    return 4;
-  else if (value < 0x0000010000000000ULL)
-    return 5;
-  else if (value < 0x0001000000000000ULL)
-    return 6;
-  else if (value < 0x0100000000000000ULL)
-    return 7;
-  return 8;
-}
-
-int32 GetIntSize(int64 value) {
-  // Doubling the requested value ensures positive values with their high bit
-  // set are written with 0-padding to avoid flipping the signedness.
-  const uint64 v = (value < 0) ? value ^ -1LL : value;
-  return GetUIntSize(2 * v);
-}
-
-uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
-  // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += GetCodedUIntSize(value);
-
-  return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, int64 value) {
-  // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += GetIntSize(value);
-
-  // Size of Datasize
-  ebml_size++;
-
-  return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, uint64 value) {
-  // Size of EBML ID
-  int32 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += GetUIntSize(value);
-
-  // Size of Datasize
-  ebml_size++;
-
-  return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, float /* value */) {
-  // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += sizeof(float);
-
-  // Size of Datasize
-  ebml_size++;
-
-  return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, const char* value) {
-  if (!value)
-    return 0;
-
-  // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += strlen(value);
-
-  // Size of Datasize
-  ebml_size++;
-
-  return ebml_size;
-}
-
-uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
-  if (!value)
-    return 0;
-
-  // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += size;
-
-  // Size of Datasize
-  ebml_size += GetCodedUIntSize(size);
-
-  return ebml_size;
-}
-
-uint64 EbmlDateElementSize(uint64 type) {
-  // Size of EBML ID
-  uint64 ebml_size = GetUIntSize(type);
-
-  // Datasize
-  ebml_size += kDateElementSize;
-
-  // Size of Datasize
-  ebml_size++;
-
-  return ebml_size;
-}
-
-int32 SerializeInt(IMkvWriter* writer, int64 value, int32 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;
-
-    const int64 bb = value >> bit_count;
-    const uint8 b = static_cast<uint8>(bb);
-
-    const int32 status = writer->Write(&b, 1);
-
-    if (status < 0)
-      return status;
-  }
-
-  return 0;
-}
-
-int32 SerializeFloat(IMkvWriter* writer, float f) {
-  if (!writer)
-    return -1;
-
-  assert(sizeof(uint32) == sizeof(float));
-  // This union is merely used to avoid a reinterpret_cast from float& to
-  // uint32& which will result in violation of strict aliasing.
-  union U32 {
-    uint32 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;
-
-    const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
-
-    const int32 status = writer->Write(&byte, 1);
-
-    if (status < 0)
-      return status;
-  }
-
-  return 0;
-}
-
-int32 WriteUInt(IMkvWriter* writer, uint64 value) {
-  if (!writer)
-    return -1;
-
-  int32 size = GetCodedUIntSize(value);
-
-  return WriteUIntSize(writer, value, size);
-}
-
-int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
-  if (!writer || size < 0 || size > 8)
-    return -1;
-
-  if (size > 0) {
-    const uint64 bit = 1LL << (size * 7);
-
-    if (value > (bit - 2))
-      return -1;
-
-    value |= bit;
-  } else {
-    size = 1;
-    int64 bit;
-
-    for (;;) {
-      bit = 1LL << (size * 7);
-      const uint64 max = bit - 2;
-
-      if (value <= max)
-        break;
-
-      ++size;
-    }
-
-    if (size > 8)
-      return false;
-
-    value |= bit;
-  }
-
-  return SerializeInt(writer, value, size);
-}
-
-int32 WriteID(IMkvWriter* writer, uint64 type) {
-  if (!writer)
-    return -1;
-
-  writer->ElementStartNotify(type, writer->Position());
-
-  const int32 size = GetUIntSize(type);
-
-  return SerializeInt(writer, type, size);
-}
-
-bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
-  if (!writer)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  if (WriteUInt(writer, size))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
-  if (!writer)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  const uint64 size = GetUIntSize(value);
-  if (WriteUInt(writer, size))
-    return false;
-
-  if (SerializeInt(writer, value, static_cast<int32>(size)))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
-  if (!writer)
-    return false;
-
-  if (WriteID(writer, type))
-    return 0;
-
-  const uint64 size = GetIntSize(value);
-  if (WriteUInt(writer, size))
-    return false;
-
-  if (SerializeInt(writer, value, static_cast<int32>(size)))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
-  if (!writer)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  if (WriteUInt(writer, 4))
-    return false;
-
-  if (SerializeFloat(writer, value))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
-  if (!writer || !value)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  const uint64 length = strlen(value);
-  if (WriteUInt(writer, length))
-    return false;
-
-  if (writer->Write(value, static_cast<const uint32>(length)))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
-                      uint64 size) {
-  if (!writer || !value || size < 1)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  if (WriteUInt(writer, size))
-    return false;
-
-  if (writer->Write(value, static_cast<uint32>(size)))
-    return false;
-
-  return true;
-}
-
-bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
-  if (!writer)
-    return false;
-
-  if (WriteID(writer, type))
-    return false;
-
-  if (WriteUInt(writer, kDateElementSize))
-    return false;
-
-  if (SerializeInt(writer, value, kDateElementSize))
-    return false;
-
-  return true;
-}
-
-uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
-                  Cluster* cluster) {
-  if (!writer || !frame || !frame->IsValid() || !cluster ||
-      !cluster->timecode_scale())
-    return 0;
-
-  //  Technically the timecode for a block can be less than the
-  //  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(
-      frame->timestamp() / cluster->timecode_scale());
-  if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
-    return 0;
-
-  return frame->CanBeSimpleBlock() ?
-             WriteSimpleBlock(writer, frame, relative_timecode) :
-             WriteBlock(writer, frame, relative_timecode,
-                        cluster->timecode_scale());
-}
-
-uint64 WriteVoidElement(IMkvWriter* writer, uint64 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;
-
-  if (void_size != size)
-    return 0;
-
-  const int64 payload_position = writer->Position();
-  if (payload_position < 0)
-    return 0;
-
-  if (WriteID(writer, 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) {
-    if (writer->Write(&value, 1))
-      return 0;
-  }
-
-  const int64 stop_position = writer->Position();
-  if (stop_position < 0 ||
-      stop_position - payload_position != static_cast<int64>(void_size))
-    return 0;
-
-  return void_size;
-}
-
-void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
-  *major = 0;
-  *minor = 2;
-  *build = 1;
-  *revision = 0;
-}
-
-}  // namespace mkvmuxer
-
-mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
-  uint64 uid = 0;
-
-#ifdef __MINGW32__
-  srand(*seed);
-#endif
-
-  for (int i = 0; i < 7; ++i) {  // avoid problems with 8-byte values
-    uid <<= 8;
-
-// TODO(fgalligan): Move random number generation to platform specific code.
-#ifdef _MSC_VER
-    (void)seed;
-    const int32 nn = rand();
-#elif __ANDROID__
-    int32 temp_num = 1;
-    int fd = open("/dev/urandom", O_RDONLY);
-    if (fd != -1) {
-      read(fd, &temp_num, sizeof(int32));
-      close(fd);
-    }
-    const int32 nn = temp_num;
-#elif defined __MINGW32__
-    const int32 nn = rand();
-#else
-    const int32 nn = rand_r(seed);
-#endif
-    const int32 n = 0xFF & (nn >> 4);  // throw away low-order bits
-
-    uid |= n;
-  }
-
-  return uid;
-}
diff --git a/third_party/libwebm/mkvmuxerutil.hpp b/third_party/libwebm/mkvmuxerutil.hpp
deleted file mode 100644
index e318576..0000000
--- a/third_party/libwebm/mkvmuxerutil.hpp
+++ /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
diff --git a/third_party/libwebm/mkvparser.cpp b/third_party/libwebm/mkvparser/mkvparser.cc
similarity index 91%
rename from third_party/libwebm/mkvparser.cpp
rename to third_party/libwebm/mkvparser/mkvparser.cc
index f2855d5..2180115 100644
--- a/third_party/libwebm/mkvparser.cpp
+++ b/third_party/libwebm/mkvparser/mkvparser.cc
@@ -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()
@@ -14,19 +13,18 @@
 #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 @@
 
 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 @@
   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 @@
 
   // 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 @@
     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 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 @@
   if ((available - pos) < result)
     return pos + result;
 
-  end = pos + result;
+  const long long end = pos + result;
 
   Init();
 
@@ -599,27 +598,27 @@
     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 @@
 
       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 @@
     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 @@
     // 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 @@
     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 @@
     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 @@
 
       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 @@
 
       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 @@
         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 @@
         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 @@
         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 @@
       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 @@
       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 @@
     return E_FILE_FORMAT_INVALID;
 
   for (;;) {
-    const int status = LoadCluster();
+    const long status = LoadCluster();
 
     if (status < 0)  // error
       return status;
@@ -1512,9 +1511,9 @@
     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 @@
     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 @@
 
   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 @@
   if (seekIdId < 0)
     return false;
 
-  if (seekIdId != mkvmuxer::kMkvSeekID)
+  if (seekIdId != libwebm::kMkvSeekID)
     return false;
 
   if ((pos + len) > stop)
@@ -1790,7 +1789,7 @@
 
   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 @@
       return false;
     }
 
-    if (id == mkvmuxer::kMkvCuePoint) {
+    if (id == libwebm::kMkvCuePoint) {
       if (!PreloadCuePoint(cue_points_size, idpos))
         return false;
     }
@@ -1975,7 +1974,7 @@
     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::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 @@
     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 @@
       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 @@
     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 @@
       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 @@
       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 @@
     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 @@
 
     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 @@
       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 @@
       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 @@
       // 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 @@
     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 @@
     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 @@
     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 @@
         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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 
       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 @@
     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 @@
     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 @@
     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 @@
         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 @@
     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 @@
     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 @@
 
       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 @@
 
       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 @@
 
       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 @@
       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 @@
       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 @@
 
 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 @@
 
   const long long stop = pos + s.size;
 
+  Colour* colour = NULL;
+
   while (pos < stop) {
     long long id, size;
 
@@ -5019,37 +5233,37 @@
     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 @@
 
       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 @@
   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 @@
   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 @@
     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 @@
 
       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 @@
     if (size == 0)  // weird
       continue;
 
-    if (id == mkvmuxer::kMkvTrackEntry)
+    if (id == libwebm::kMkvTrackEntry)
       ++count;
 
     pos += size;  // consume payload
@@ -5367,7 +5587,7 @@
 
     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 @@
 
     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 @@
 
         ++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 @@
         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 @@
   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 @@
     // 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 @@
     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 @@
 
       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 @@
     // 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 @@
 
     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 @@
 
     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 @@
     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 @@
     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 @@
   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 @@
     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 @@
     // 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 @@
     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 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 @@
     }
   }
 
-  if (id == mkvmuxer::kMkvBlockGroup)
+  if (id == libwebm::kMkvBlockGroup)
     return CreateBlockGroup(pos, size, discard_padding);
   else
     return CreateSimpleBlock(pos, size);
@@ -6871,12 +7089,12 @@
 
     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 @@
 
       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 @@
 
 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 @@
       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 @@
       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 long Block::GetDiscardPadding() const { return m_discard_padding; }
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
diff --git a/third_party/libwebm/mkvparser.hpp b/third_party/libwebm/mkvparser/mkvparser.h
similarity index 89%
rename from third_party/libwebm/mkvparser.hpp
rename to third_party/libwebm/mkvparser/mkvparser.h
index 75ef69d..42e6e88 100644
--- a/third_party/libwebm/mkvparser.hpp
+++ b/third_party/libwebm/mkvparser/mkvparser.h
@@ -5,13 +5,10 @@
 // tree. An additional intellectual property rights grant can be found
 // in the file PATENTS.  All contributing project authors may
 // be found in the AUTHORS file in the root of the source tree.
-
-#ifndef MKVPARSER_HPP
-#define MKVPARSER_HPP
+#ifndef MKVPARSER_MKVPARSER_H_
+#define MKVPARSER_MKVPARSER_H_
 
 #include <cstddef>
-#include <cstdio>
-#include <cstdlib>
 
 namespace mkvparser {
 
@@ -28,8 +25,9 @@
   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 @@
  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 @@
   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 @@
   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 @@
   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 @@
   long long m_stereo_mode;
 
   double m_rate;
+
+  Colour* m_colour;
 };
 
 class AudioTrack : public Track {
@@ -1013,7 +1100,7 @@
   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 @@
   return LoadCluster(pos, size);
 }
 
-#endif  // MKVPARSER_HPP
+#endif  // MKVPARSER_MKVPARSER_H_
diff --git a/third_party/libwebm/mkvreader.cpp b/third_party/libwebm/mkvparser/mkvreader.cc
similarity index 96%
rename from third_party/libwebm/mkvreader.cpp
rename to third_party/libwebm/mkvparser/mkvreader.cc
index eaf9e0a..9f90d8c 100644
--- a/third_party/libwebm/mkvreader.cpp
+++ b/third_party/libwebm/mkvparser/mkvreader.cc
@@ -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 @@
   return 0;  // success
 }
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
\ No newline at end of file
diff --git a/third_party/libwebm/mkvreader.hpp b/third_party/libwebm/mkvparser/mkvreader.h
similarity index 86%
rename from third_party/libwebm/mkvreader.hpp
rename to third_party/libwebm/mkvparser/mkvreader.h
index 82ebad5..9831ecf 100644
--- a/third_party/libwebm/mkvreader.hpp
+++ b/third_party/libwebm/mkvparser/mkvreader.h
@@ -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 @@
   bool reader_owns_file_;
 };
 
-}  // end namespace mkvparser
+}  // namespace mkvparser
 
-#endif  // MKVREADER_HPP
+#endif  // MKVPARSER_MKVREADER_H_
diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h
index 4ed7f81..fbcba09 100644
--- a/vp10/common/blockd.h
+++ b/vp10/common/blockd.h
@@ -705,7 +705,11 @@
 
 #if CONFIG_OBMC
 static INLINE int is_obmc_allowed(const MB_MODE_INFO *mbmi) {
+#if CONFIG_EXT_INTER
+  return (mbmi->sb_type >= BLOCK_8X8 && mbmi->ref_frame[1] != INTRA_FRAME);
+#else
   return (mbmi->sb_type >= BLOCK_8X8);
+#endif  // CONFIG_EXT_INTER
 }
 
 static INLINE int is_neighbor_overlappable(const MB_MODE_INFO *mbmi) {
diff --git a/vp10/common/idct.c b/vp10/common/idct.c
index b06a5e9..b7da81b 100644
--- a/vp10/common/idct.c
+++ b/vp10/common/idct.c
@@ -24,11 +24,7 @@
   (void) tx_type;
 #if CONFIG_VP9_HIGHBITDEPTH
   if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
-    if (xd->bd == BITDEPTH_10) {
-      return 0;
-    } else {
-      return tx_size == TX_32X32;
-    }
+    return tx_size == TX_32X32;
   }
 #else
   (void)xd;
@@ -1306,16 +1302,20 @@
 
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10)
-        vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
-                                &inv_txfm_2d_cfg_dct_dct_4, bd);
-      else
-        vp10_highbd_idct4x4_add(input, dest, stride, eob, bd);
+      vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_dct_dct_4, bd);
       break;
     case ADST_DCT:
+      vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_adst_dct_4, bd);
+      break;
     case DCT_ADST:
+      vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_dct_adst_4, bd);
+      break;
     case ADST_ADST:
-      vp10_highbd_iht4x4_16_add(input, dest, stride, tx_type, bd);
+      vp10_inv_txfm2d_add_4x4(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_adst_adst_4, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -1347,18 +1347,23 @@
 void vp10_highbd_inv_txfm_add_8x8(const tran_low_t *input, uint8_t *dest,
                                   int stride, int eob, int bd,
                                   TX_TYPE tx_type) {
+  (void)eob;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10)
-        vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
-                                &inv_txfm_2d_cfg_dct_dct_8, bd);
-      else
-        vp10_highbd_idct8x8_add(input, dest, stride, eob, bd);
+      vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_dct_dct_8, bd);
       break;
     case ADST_DCT:
+      vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_adst_dct_8, bd);
+      break;
     case DCT_ADST:
+      vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_dct_adst_8, bd);
+      break;
     case ADST_ADST:
-      vp10_highbd_iht8x8_64_add(input, dest, stride, tx_type, bd);
+      vp10_inv_txfm2d_add_8x8(input, CONVERT_TO_SHORTPTR(dest), stride,
+                              &inv_txfm_2d_cfg_adst_adst_8, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -1390,18 +1395,23 @@
 void vp10_highbd_inv_txfm_add_16x16(const tran_low_t *input, uint8_t *dest,
                                     int stride, int eob, int bd,
                                     TX_TYPE tx_type) {
+  (void)eob;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10)
-        vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
-                                  &inv_txfm_2d_cfg_dct_dct_16, bd);
-      else
-        vp10_highbd_idct16x16_add(input, dest, stride, eob, bd);
+      vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+                                &inv_txfm_2d_cfg_dct_dct_16, bd);
       break;
     case ADST_DCT:
+      vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+                                &inv_txfm_2d_cfg_adst_dct_16, bd);
+      break;
     case DCT_ADST:
+      vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+                                &inv_txfm_2d_cfg_dct_adst_16, bd);
+      break;
     case ADST_ADST:
-      vp10_highbd_iht16x16_256_add(input, dest, stride, tx_type, bd);
+      vp10_inv_txfm2d_add_16x16(input, CONVERT_TO_SHORTPTR(dest), stride,
+                                &inv_txfm_2d_cfg_adst_adst_16, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -1433,13 +1443,11 @@
 void vp10_highbd_inv_txfm_add_32x32(const tran_low_t *input, uint8_t *dest,
                                     int stride, int eob, int bd,
                                     TX_TYPE tx_type) {
+  (void)eob;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10)
-        vp10_inv_txfm2d_add_32x32(input, CONVERT_TO_SHORTPTR(dest), stride,
-                                  &inv_txfm_2d_cfg_dct_dct_32, bd);
-      else
-        vp10_highbd_idct32x32_add(input, dest, stride, eob, bd);
+      vp10_inv_txfm2d_add_32x32(input, CONVERT_TO_SHORTPTR(dest), stride,
+                                &inv_txfm_2d_cfg_dct_dct_32, bd);
       break;
 #if CONFIG_EXT_TX
     case ADST_DCT:
diff --git a/vp10/common/mvref_common.c b/vp10/common/mvref_common.c
index 7c6633f..3023589 100644
--- a/vp10/common/mvref_common.c
+++ b/vp10/common/mvref_common.c
@@ -61,6 +61,8 @@
           int alt_block = 3 - block;
           this_refmv =
               get_sub_block_mv(candidate_mi, ref, col, alt_block);
+          lower_mv_precision(&this_refmv.as_mv, use_hp);
+
           for (index = 0; index < *refmv_count; ++index)
             if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int)
               break;
@@ -95,6 +97,9 @@
           get_sub_block_mv(candidate_mi, 1, col, block)
       };
 
+      for (ref = 0; ref < 2; ++ref)
+        lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
+
       for (index = 0; index < *refmv_count; ++index)
         if ((ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int) &&
             (ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int))
@@ -123,6 +128,9 @@
         this_refmv[0] = get_sub_block_mv(candidate_mi, 0, col, alt_block);
         this_refmv[1] = get_sub_block_mv(candidate_mi, 1, col, alt_block);
 
+        for (ref = 0; ref < 2; ++ref)
+          lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
+
         for (index = 0; index < *refmv_count; ++index)
           if (ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int &&
               ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int)
diff --git a/vp10/common/scan.c b/vp10/common/scan.c
index 9fef038..8cfeb97 100644
--- a/vp10/common/scan.c
+++ b/vp10/common/scan.c
@@ -787,10 +787,8 @@
 };
 #endif  // CONFIG_EXT_TX
 
-// Neighborhood 5-tuples for various scans and blocksizes,
-// in {top, left, topleft, topright, bottomleft} order
-// for each position in raster scan order.
-// -1 indicates the neighbor does not exist.
+// Neighborhood 2-tuples for various scans and blocksizes,
+// in {top, left} order for each position in corresponding scan order.
 DECLARE_ALIGNED(16, static const int16_t,
                 default_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
   0,   0,   0,   0,   4,   0,   1,   4,   4,   5,   5,   1,
@@ -2964,7 +2962,7 @@
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
-    {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
+    {mrow_scan_4x4,    vp10_mrow_iscan_4x4,    mrow_scan_4x4_neighbors},
     {row_scan_4x4,     vp10_row_iscan_4x4,     row_scan_4x4_neighbors},
     {col_scan_4x4,     vp10_col_iscan_4x4,     col_scan_4x4_neighbors},
     {row_scan_4x4,     vp10_row_iscan_4x4,     row_scan_4x4_neighbors},
@@ -2981,7 +2979,7 @@
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
-    {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
+    {mrow_scan_8x8,    vp10_mrow_iscan_8x8,    mrow_scan_8x8_neighbors},
     {row_scan_8x8,     vp10_row_iscan_8x8,     row_scan_8x8_neighbors},
     {col_scan_8x8,     vp10_col_iscan_8x8,     col_scan_8x8_neighbors},
     {row_scan_8x8,     vp10_row_iscan_8x8,     row_scan_8x8_neighbors},
@@ -3005,8 +3003,7 @@
      default_scan_16x16_neighbors},
     {default_scan_16x16, vp10_default_iscan_16x16,
      default_scan_16x16_neighbors},
-    {default_scan_16x16, vp10_default_iscan_16x16,
-     default_scan_16x16_neighbors},
+    {mrow_scan_16x16,  vp10_mrow_iscan_16x16,  mrow_scan_16x16_neighbors},
     {row_scan_16x16,     vp10_row_iscan_16x16,     row_scan_16x16_neighbors},
     {col_scan_16x16,     vp10_col_iscan_16x16,     col_scan_16x16_neighbors},
     {row_scan_16x16,     vp10_row_iscan_16x16,     row_scan_16x16_neighbors},
@@ -3032,8 +3029,7 @@
      qtr_scan_32x32_neighbors},
     {qtr_scan_32x32, vp10_qtr_iscan_32x32,
      qtr_scan_32x32_neighbors},
-    {default_scan_32x32, vp10_default_iscan_32x32,
-     default_scan_32x32_neighbors},
+    {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
     {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
     {mcol_scan_32x32,  vp10_mcol_iscan_32x32,  mcol_scan_32x32_neighbors},
     {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
@@ -3054,7 +3050,7 @@
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
     {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
-    {default_scan_4x4, vp10_default_iscan_4x4, default_scan_4x4_neighbors},
+    {mrow_scan_4x4,    vp10_mrow_iscan_4x4,    mrow_scan_4x4_neighbors},
     {mrow_scan_4x4,    vp10_mrow_iscan_4x4,    mrow_scan_4x4_neighbors},
     {mcol_scan_4x4,    vp10_mcol_iscan_4x4,    mcol_scan_4x4_neighbors},
     {mrow_scan_4x4,    vp10_mrow_iscan_4x4,    mrow_scan_4x4_neighbors},
@@ -3071,7 +3067,7 @@
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
     {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
-    {default_scan_8x8, vp10_default_iscan_8x8, default_scan_8x8_neighbors},
+    {mrow_scan_8x8,    vp10_mrow_iscan_8x8,    mrow_scan_8x8_neighbors},
     {mrow_scan_8x8,    vp10_mrow_iscan_8x8,    mrow_scan_8x8_neighbors},
     {mcol_scan_8x8,    vp10_mcol_iscan_8x8,    mcol_scan_8x8_neighbors},
     {mrow_scan_8x8,    vp10_mrow_iscan_8x8,    mrow_scan_8x8_neighbors},
@@ -3097,8 +3093,7 @@
      default_scan_16x16_neighbors},
     {default_scan_16x16, vp10_default_iscan_16x16,
      default_scan_16x16_neighbors},
-    {default_scan_16x16, vp10_default_iscan_16x16,
-     default_scan_16x16_neighbors},
+    {mrow_scan_16x16,  vp10_mrow_iscan_16x16,  mrow_scan_16x16_neighbors},
     {mrow_scan_16x16,  vp10_mrow_iscan_16x16,  mrow_scan_16x16_neighbors},
     {mcol_scan_16x16,  vp10_mcol_iscan_16x16,  mcol_scan_16x16_neighbors},
     {mrow_scan_16x16,  vp10_mrow_iscan_16x16,  mrow_scan_16x16_neighbors},
@@ -3124,8 +3119,7 @@
      qtr_scan_32x32_neighbors},
     {qtr_scan_32x32, vp10_qtr_iscan_32x32,
      qtr_scan_32x32_neighbors},
-    {default_scan_32x32, vp10_default_iscan_32x32,
-     default_scan_32x32_neighbors},
+    {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
     {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
     {mcol_scan_32x32,  vp10_mcol_iscan_32x32,  mcol_scan_32x32_neighbors},
     {mrow_scan_32x32,  vp10_mrow_iscan_32x32,  mrow_scan_32x32_neighbors},
diff --git a/vp10/common/vp10_fwd_txfm2d.c b/vp10/common/vp10_fwd_txfm2d.c
index dd7101a..d54a174 100644
--- a/vp10/common/vp10_fwd_txfm2d.c
+++ b/vp10/common/vp10_fwd_txfm2d.c
@@ -11,9 +11,6 @@
 #include "vp10/common/vp10_txfm.h"
 #include "vp10/common/vp10_fwd_txfm1d.h"
 
-typedef void (*TxfmFunc)(const int32_t *input, int32_t *output,
-                         const int8_t *cos_bit, const int8_t *stage_range);
-
 static inline TxfmFunc fwd_txfm_type_to_func(TXFM_TYPE txfm_type) {
   switch (txfm_type) {
     case TXFM_TYPE_DCT4:
diff --git a/vp10/common/vp10_fwd_txfm2d_cfg.h b/vp10/common/vp10_fwd_txfm2d_cfg.h
index 3c0a906..e8c82fd 100644
--- a/vp10/common/vp10_fwd_txfm2d_cfg.h
+++ b/vp10/common/vp10_fwd_txfm2d_cfg.h
@@ -12,16 +12,17 @@
 #define VP10_FWD_TXFM2D_CFG_H_
 #include "vp10/common/vp10_fwd_txfm1d.h"
 //  ---------------- config fwd_dct_dct_4 ----------------
-static const int8_t fwd_shift_dct_dct_4[3] = {4, 0, -2};
+static const int8_t fwd_shift_dct_dct_4[3] = {2, 0, 0};
 static const int8_t fwd_stage_range_col_dct_dct_4[4] = {15, 16, 17, 17};
 static const int8_t fwd_stage_range_row_dct_dct_4[4] = {17, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_dct_dct_4[4] = {15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_dct_dct_4[4] = {15, 14, 14, 14};
+static const int8_t fwd_cos_bit_col_dct_dct_4[4] = {13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_4[4] = {13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_4 = {
-    4,                              // .txfm_size
-    4,                              // .stage_num_col
-    4,                              // .stage_num_row
+    4,  // .txfm_size
+    4,  // .stage_num_col
+    4,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_dct_4,            // .shift
     fwd_stage_range_col_dct_dct_4,  // .stage_range_col
     fwd_stage_range_row_dct_dct_4,  // .stage_range_row
@@ -31,16 +32,17 @@
     TXFM_TYPE_DCT4};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_dct_8 ----------------
-static const int8_t fwd_shift_dct_dct_8[3] = {5, -3, -1};
-static const int8_t fwd_stage_range_col_dct_dct_8[6] = {16, 17, 18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_dct_8[6] = {16, 17, 18, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_dct_dct_8[6] = {15, 15, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_8[6] = {15, 15, 14, 14, 14, 14};
+static const int8_t fwd_shift_dct_dct_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_dct_dct_8[6] = {15, 16, 17, 18, 18, 18};
+static const int8_t fwd_stage_range_row_dct_dct_8[6] = {17, 18, 19, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_8 = {
-    8,                              // .txfm_size
-    6,                              // .stage_num_col
-    6,                              // .stage_num_row
+    8,  // .txfm_size
+    6,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_dct_8,            // .shift
     fwd_stage_range_col_dct_dct_8,  // .stage_range_col
     fwd_stage_range_row_dct_dct_8,  // .stage_range_row
@@ -50,20 +52,21 @@
     TXFM_TYPE_DCT8};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_dct_16 ----------------
-static const int8_t fwd_shift_dct_dct_16[3] = {4, -3, -1};
+static const int8_t fwd_shift_dct_dct_16[3] = {2, -2, 0};
 static const int8_t fwd_stage_range_col_dct_dct_16[8] = {15, 16, 17, 18,
                                                          19, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_dct_16[8] = {16, 17, 18, 19,
-                                                         19, 19, 19, 19};
-static const int8_t fwd_cos_bit_col_dct_dct_16[8] = {15, 15, 15, 14,
+static const int8_t fwd_stage_range_row_dct_dct_16[8] = {17, 18, 19, 20,
+                                                         20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_dct_16[8] = {13, 13, 13, 13,
                                                      13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_16[8] = {15, 15, 14, 13,
-                                                     13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_dct_16[8] = {12, 12, 12, 12,
+                                                     12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_16 = {
-    16,                              // .txfm_size
-    8,                               // .stage_num_col
-    8,                               // .stage_num_row
+    16,  // .txfm_size
+    8,   // .stage_num_col
+    8,   // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_dct_16,            // .shift
     fwd_stage_range_col_dct_dct_16,  // .stage_range_col
     fwd_stage_range_row_dct_dct_16,  // .stage_range_row
@@ -73,20 +76,21 @@
     TXFM_TYPE_DCT16};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_dct_32 ----------------
-static const int8_t fwd_shift_dct_dct_32[3] = {3, -3, -1};
-static const int8_t fwd_stage_range_col_dct_dct_32[10] = {14, 15, 16, 17, 18,
-                                                          19, 19, 19, 19, 19};
+static const int8_t fwd_shift_dct_dct_32[3] = {2, -4, 0};
+static const int8_t fwd_stage_range_col_dct_dct_32[10] = {15, 16, 17, 18, 19,
+                                                          20, 20, 20, 20, 20};
 static const int8_t fwd_stage_range_row_dct_dct_32[10] = {16, 17, 18, 19, 20,
                                                           20, 20, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_dct_dct_32[10] = {15, 15, 15, 15, 14,
-                                                      13, 13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_dct_32[10] = {15, 15, 14, 13, 12,
+static const int8_t fwd_cos_bit_col_dct_dct_32[10] = {12, 12, 12, 12, 12,
+                                                      12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_dct_dct_32[10] = {12, 12, 12, 12, 12,
                                                       12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_dct_32 = {
-    32,                              // .txfm_size
-    10,                              // .stage_num_col
-    10,                              // .stage_num_row
+    32,  // .txfm_size
+    10,  // .stage_num_col
+    10,  // .stage_num_row
+    // 1,  // .log_scale
     fwd_shift_dct_dct_32,            // .shift
     fwd_stage_range_col_dct_dct_32,  // .stage_range_col
     fwd_stage_range_row_dct_dct_32,  // .stage_range_row
@@ -119,17 +123,18 @@
     TXFM_TYPE_DCT64};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_adst_4 ----------------
-static const int8_t fwd_shift_dct_adst_4[3] = {5, -2, -1};
-static const int8_t fwd_stage_range_col_dct_adst_4[4] = {16, 17, 18, 18};
-static const int8_t fwd_stage_range_row_dct_adst_4[6] = {16, 16, 16,
-                                                         17, 17, 17};
-static const int8_t fwd_cos_bit_col_dct_adst_4[4] = {15, 15, 14, 14};
-static const int8_t fwd_cos_bit_row_dct_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t fwd_shift_dct_adst_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_dct_adst_4[4] = {15, 16, 17, 17};
+static const int8_t fwd_stage_range_row_dct_adst_4[6] = {17, 17, 17,
+                                                         18, 18, 18};
+static const int8_t fwd_cos_bit_col_dct_adst_4[4] = {13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_adst_4[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_4 = {
-    4,                               // .txfm_size
-    4,                               // .stage_num_col
-    6,                               // .stage_num_row
+    4,  // .txfm_size
+    4,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_adst_4,            // .shift
     fwd_stage_range_col_dct_adst_4,  // .stage_range_col
     fwd_stage_range_row_dct_adst_4,  // .stage_range_row
@@ -139,19 +144,20 @@
     TXFM_TYPE_ADST4};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_adst_8 ----------------
-static const int8_t fwd_shift_dct_adst_8[3] = {7, -3, -3};
-static const int8_t fwd_stage_range_col_dct_adst_8[6] = {18, 19, 20,
-                                                         21, 21, 21};
-static const int8_t fwd_stage_range_row_dct_adst_8[8] = {18, 18, 18, 19,
-                                                         19, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_dct_adst_8[6] = {14, 13, 12, 11, 11, 11};
-static const int8_t fwd_cos_bit_row_dct_adst_8[8] = {14, 14, 14, 13,
-                                                     13, 12, 12, 12};
+static const int8_t fwd_shift_dct_adst_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_dct_adst_8[6] = {15, 16, 17,
+                                                         18, 18, 18};
+static const int8_t fwd_stage_range_row_dct_adst_8[8] = {17, 17, 17, 18,
+                                                         18, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_dct_adst_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_dct_adst_8[8] = {13, 13, 13, 13,
+                                                     13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_8 = {
-    8,                               // .txfm_size
-    6,                               // .stage_num_col
-    8,                               // .stage_num_row
+    8,  // .txfm_size
+    6,  // .stage_num_col
+    8,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_adst_8,            // .shift
     fwd_stage_range_col_dct_adst_8,  // .stage_range_col
     fwd_stage_range_row_dct_adst_8,  // .stage_range_row
@@ -161,20 +167,21 @@
     TXFM_TYPE_ADST8};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_adst_16 ----------------
-static const int8_t fwd_shift_dct_adst_16[3] = {4, -1, -3};
+static const int8_t fwd_shift_dct_adst_16[3] = {2, -2, 0};
 static const int8_t fwd_stage_range_col_dct_adst_16[8] = {15, 16, 17, 18,
                                                           19, 19, 19, 19};
-static const int8_t fwd_stage_range_row_dct_adst_16[10] = {18, 18, 18, 19, 19,
-                                                           20, 20, 21, 21, 21};
-static const int8_t fwd_cos_bit_col_dct_adst_16[8] = {15, 15, 15, 14,
+static const int8_t fwd_stage_range_row_dct_adst_16[10] = {17, 17, 17, 18, 18,
+                                                           19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_adst_16[8] = {13, 13, 13, 13,
                                                       13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_adst_16[10] = {14, 14, 14, 13, 13,
-                                                       12, 12, 11, 11, 11};
+static const int8_t fwd_cos_bit_row_dct_adst_16[10] = {12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_16 = {
-    16,                               // .txfm_size
-    8,                                // .stage_num_col
-    10,                               // .stage_num_row
+    16,  // .txfm_size
+    8,   // .stage_num_col
+    10,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_dct_adst_16,            // .shift
     fwd_stage_range_col_dct_adst_16,  // .stage_range_col
     fwd_stage_range_row_dct_adst_16,  // .stage_range_row
@@ -184,20 +191,21 @@
     TXFM_TYPE_ADST16};                // .txfm_type_row
 
 //  ---------------- config fwd_dct_adst_32 ----------------
-static const int8_t fwd_shift_dct_adst_32[3] = {3, -1, -3};
-static const int8_t fwd_stage_range_col_dct_adst_32[10] = {14, 15, 16, 17, 18,
-                                                           19, 19, 19, 19, 19};
+static const int8_t fwd_shift_dct_adst_32[3] = {2, -4, 0};
+static const int8_t fwd_stage_range_col_dct_adst_32[10] = {15, 16, 17, 18, 19,
+                                                           20, 20, 20, 20, 20};
 static const int8_t fwd_stage_range_row_dct_adst_32[12] = {
-    18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 22};
-static const int8_t fwd_cos_bit_col_dct_adst_32[10] = {15, 15, 15, 15, 14,
-                                                       13, 13, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_dct_adst_32[12] = {14, 14, 14, 13, 13, 12,
-                                                       12, 11, 11, 10, 10, 10};
+    16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_dct_adst_32[10] = {12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_dct_adst_32[12] = {12, 12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_dct_adst_32 = {
-    32,                               // .txfm_size
-    10,                               // .stage_num_col
-    12,                               // .stage_num_row
+    32,  // .txfm_size
+    10,  // .stage_num_col
+    12,  // .stage_num_row
+    // 1,  // .log_scale
     fwd_shift_dct_adst_32,            // .shift
     fwd_stage_range_col_dct_adst_32,  // .stage_range_col
     fwd_stage_range_row_dct_adst_32,  // .stage_range_row
@@ -205,20 +213,20 @@
     fwd_cos_bit_row_dct_adst_32,      // .cos_bit_row
     TXFM_TYPE_DCT32,                  // .txfm_type_col
     TXFM_TYPE_ADST32};                // .txfm_type_row
-
 //  ---------------- config fwd_adst_adst_4 ----------------
-static const int8_t fwd_shift_adst_adst_4[3] = {6, 1, -5};
-static const int8_t fwd_stage_range_col_adst_adst_4[6] = {17, 17, 18,
-                                                          19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_adst_4[6] = {20, 20, 20,
-                                                          21, 21, 21};
-static const int8_t fwd_cos_bit_col_adst_adst_4[6] = {15, 15, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_adst_4[6] = {12, 12, 12, 11, 11, 11};
+static const int8_t fwd_shift_adst_adst_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_adst_adst_4[6] = {15, 15, 16,
+                                                          17, 17, 17};
+static const int8_t fwd_stage_range_row_adst_adst_4[6] = {17, 17, 17,
+                                                          18, 18, 18};
+static const int8_t fwd_cos_bit_col_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_4 = {
-    4,                                // .txfm_size
-    6,                                // .stage_num_col
-    6,                                // .stage_num_row
+    4,  // .txfm_size
+    6,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_adst_4,            // .shift
     fwd_stage_range_col_adst_adst_4,  // .stage_range_col
     fwd_stage_range_row_adst_adst_4,  // .stage_range_row
@@ -228,20 +236,21 @@
     TXFM_TYPE_ADST4};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_adst_8 ----------------
-static const int8_t fwd_shift_adst_adst_8[3] = {3, -1, -1};
-static const int8_t fwd_stage_range_col_adst_adst_8[8] = {14, 14, 15, 16,
-                                                          16, 17, 17, 17};
-static const int8_t fwd_stage_range_row_adst_adst_8[8] = {16, 16, 16, 17,
+static const int8_t fwd_shift_adst_adst_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_adst_adst_8[8] = {15, 15, 16, 17,
                                                           17, 18, 18, 18};
-static const int8_t fwd_cos_bit_col_adst_adst_8[8] = {15, 15, 15, 15,
-                                                      15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_adst_adst_8[8] = {15, 15, 15, 15,
-                                                      15, 14, 14, 14};
+static const int8_t fwd_stage_range_row_adst_adst_8[8] = {17, 17, 17, 18,
+                                                          18, 19, 19, 19};
+static const int8_t fwd_cos_bit_col_adst_adst_8[8] = {13, 13, 13, 13,
+                                                      13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_8[8] = {13, 13, 13, 13,
+                                                      13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_8 = {
-    8,                                // .txfm_size
-    8,                                // .stage_num_col
-    8,                                // .stage_num_row
+    8,  // .txfm_size
+    8,  // .stage_num_col
+    8,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_adst_8,            // .shift
     fwd_stage_range_col_adst_adst_8,  // .stage_range_col
     fwd_stage_range_row_adst_adst_8,  // .stage_range_row
@@ -251,20 +260,21 @@
     TXFM_TYPE_ADST8};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_adst_16 ----------------
-static const int8_t fwd_shift_adst_adst_16[3] = {2, 0, -2};
-static const int8_t fwd_stage_range_col_adst_adst_16[10] = {13, 13, 14, 15, 15,
-                                                            16, 16, 17, 17, 17};
+static const int8_t fwd_shift_adst_adst_16[3] = {2, -2, 0};
+static const int8_t fwd_stage_range_col_adst_adst_16[10] = {15, 15, 16, 17, 17,
+                                                            18, 18, 19, 19, 19};
 static const int8_t fwd_stage_range_row_adst_adst_16[10] = {17, 17, 17, 18, 18,
                                                             19, 19, 20, 20, 20};
-static const int8_t fwd_cos_bit_col_adst_adst_16[10] = {15, 15, 15, 15, 15,
-                                                        15, 15, 15, 15, 15};
-static const int8_t fwd_cos_bit_row_adst_adst_16[10] = {15, 15, 15, 14, 14,
-                                                        13, 13, 12, 12, 12};
+static const int8_t fwd_cos_bit_col_adst_adst_16[10] = {13, 13, 13, 13, 13,
+                                                        13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_adst_16[10] = {12, 12, 12, 12, 12,
+                                                        12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_16 = {
-    16,                                // .txfm_size
-    10,                                // .stage_num_col
-    10,                                // .stage_num_row
+    16,  // .txfm_size
+    10,  // .stage_num_col
+    10,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_adst_16,            // .shift
     fwd_stage_range_col_adst_adst_16,  // .stage_range_col
     fwd_stage_range_row_adst_adst_16,  // .stage_range_row
@@ -274,20 +284,21 @@
     TXFM_TYPE_ADST16};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_adst_32 ----------------
-static const int8_t fwd_shift_adst_adst_32[3] = {4, -2, -3};
+static const int8_t fwd_shift_adst_adst_32[3] = {2, -4, 0};
 static const int8_t fwd_stage_range_col_adst_adst_32[12] = {
     15, 15, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
 static const int8_t fwd_stage_range_row_adst_adst_32[12] = {
-    18, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 22};
-static const int8_t fwd_cos_bit_col_adst_adst_32[12] = {15, 15, 15, 15, 15, 14,
-                                                        14, 13, 13, 12, 12, 12};
-static const int8_t fwd_cos_bit_row_adst_adst_32[12] = {14, 14, 14, 13, 13, 12,
-                                                        12, 11, 11, 10, 10, 10};
+    16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+                                                        12, 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+                                                        12, 12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_adst_32 = {
-    32,                                // .txfm_size
-    12,                                // .stage_num_col
-    12,                                // .stage_num_row
+    32,  // .txfm_size
+    12,  // .stage_num_col
+    12,  // .stage_num_row
+    // 1,  // .log_scale
     fwd_shift_adst_adst_32,            // .shift
     fwd_stage_range_col_adst_adst_32,  // .stage_range_col
     fwd_stage_range_row_adst_adst_32,  // .stage_range_row
@@ -297,17 +308,18 @@
     TXFM_TYPE_ADST32};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_dct_4 ----------------
-static const int8_t fwd_shift_adst_dct_4[3] = {5, -4, 1};
-static const int8_t fwd_stage_range_col_adst_dct_4[6] = {16, 16, 17,
-                                                         18, 18, 18};
-static const int8_t fwd_stage_range_row_adst_dct_4[4] = {14, 15, 15, 15};
-static const int8_t fwd_cos_bit_col_adst_dct_4[6] = {15, 15, 15, 14, 14, 14};
-static const int8_t fwd_cos_bit_row_adst_dct_4[4] = {15, 15, 15, 15};
+static const int8_t fwd_shift_adst_dct_4[3] = {2, 0, 0};
+static const int8_t fwd_stage_range_col_adst_dct_4[6] = {15, 15, 16,
+                                                         17, 17, 17};
+static const int8_t fwd_stage_range_row_adst_dct_4[4] = {17, 18, 18, 18};
+static const int8_t fwd_cos_bit_col_adst_dct_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_4[4] = {13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_4 = {
-    4,                               // .txfm_size
-    6,                               // .stage_num_col
-    4,                               // .stage_num_row
+    4,  // .txfm_size
+    6,  // .stage_num_col
+    4,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_dct_4,            // .shift
     fwd_stage_range_col_adst_dct_4,  // .stage_range_col
     fwd_stage_range_row_adst_dct_4,  // .stage_range_row
@@ -317,19 +329,20 @@
     TXFM_TYPE_DCT4};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_dct_8 ----------------
-static const int8_t fwd_shift_adst_dct_8[3] = {5, 1, -5};
-static const int8_t fwd_stage_range_col_adst_dct_8[8] = {16, 16, 17, 18,
-                                                         18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_dct_8[6] = {20, 21, 22,
-                                                         22, 22, 22};
-static const int8_t fwd_cos_bit_col_adst_dct_8[8] = {15, 15, 15, 14,
-                                                     14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_dct_8[6] = {12, 11, 10, 10, 10, 10};
+static const int8_t fwd_shift_adst_dct_8[3] = {2, -1, 0};
+static const int8_t fwd_stage_range_col_adst_dct_8[8] = {15, 15, 16, 17,
+                                                         17, 18, 18, 18};
+static const int8_t fwd_stage_range_row_adst_dct_8[6] = {17, 18, 19,
+                                                         19, 19, 19};
+static const int8_t fwd_cos_bit_col_adst_dct_8[8] = {13, 13, 13, 13,
+                                                     13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_8[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_8 = {
-    8,                               // .txfm_size
-    8,                               // .stage_num_col
-    6,                               // .stage_num_row
+    8,  // .txfm_size
+    8,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_dct_8,            // .shift
     fwd_stage_range_col_adst_dct_8,  // .stage_range_col
     fwd_stage_range_row_adst_dct_8,  // .stage_range_row
@@ -339,20 +352,21 @@
     TXFM_TYPE_DCT8};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_dct_16 ----------------
-static const int8_t fwd_shift_adst_dct_16[3] = {4, -3, -1};
+static const int8_t fwd_shift_adst_dct_16[3] = {2, -2, 0};
 static const int8_t fwd_stage_range_col_adst_dct_16[10] = {15, 15, 16, 17, 17,
                                                            18, 18, 19, 19, 19};
-static const int8_t fwd_stage_range_row_adst_dct_16[8] = {16, 17, 18, 19,
-                                                          19, 19, 19, 19};
-static const int8_t fwd_cos_bit_col_adst_dct_16[10] = {15, 15, 15, 15, 15,
-                                                       14, 14, 13, 13, 13};
-static const int8_t fwd_cos_bit_row_adst_dct_16[8] = {15, 15, 14, 13,
-                                                      13, 13, 13, 13};
+static const int8_t fwd_stage_range_row_adst_dct_16[8] = {17, 18, 19, 20,
+                                                          20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_dct_16[10] = {13, 13, 13, 13, 13,
+                                                       13, 13, 13, 13, 13};
+static const int8_t fwd_cos_bit_row_adst_dct_16[8] = {12, 12, 12, 12,
+                                                      12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_16 = {
-    16,                               // .txfm_size
-    10,                               // .stage_num_col
-    8,                                // .stage_num_row
+    16,  // .txfm_size
+    10,  // .stage_num_col
+    8,   // .stage_num_row
+    // 0,  // .log_scale
     fwd_shift_adst_dct_16,            // .shift
     fwd_stage_range_col_adst_dct_16,  // .stage_range_col
     fwd_stage_range_row_adst_dct_16,  // .stage_range_row
@@ -362,20 +376,21 @@
     TXFM_TYPE_DCT16};                 // .txfm_type_row
 
 //  ---------------- config fwd_adst_dct_32 ----------------
-static const int8_t fwd_shift_adst_dct_32[3] = {5, -4, -2};
+static const int8_t fwd_shift_adst_dct_32[3] = {2, -4, 0};
 static const int8_t fwd_stage_range_col_adst_dct_32[12] = {
-    16, 16, 17, 18, 18, 19, 19, 20, 20, 21, 21, 21};
-static const int8_t fwd_stage_range_row_adst_dct_32[10] = {17, 18, 19, 20, 21,
-                                                           21, 21, 21, 21, 21};
-static const int8_t fwd_cos_bit_col_adst_dct_32[12] = {15, 15, 15, 14, 14, 13,
-                                                       13, 12, 12, 11, 11, 11};
-static const int8_t fwd_cos_bit_row_adst_dct_32[10] = {15, 14, 13, 12, 11,
-                                                       11, 11, 11, 11, 11};
+    15, 15, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20};
+static const int8_t fwd_stage_range_row_adst_dct_32[10] = {16, 17, 18, 19, 20,
+                                                           20, 20, 20, 20, 20};
+static const int8_t fwd_cos_bit_col_adst_dct_32[12] = {12, 12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12, 12};
+static const int8_t fwd_cos_bit_row_adst_dct_32[10] = {12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG fwd_txfm_2d_cfg_adst_dct_32 = {
-    32,                               // .txfm_size
-    12,                               // .stage_num_col
-    10,                               // .stage_num_row
+    32,  // .txfm_size
+    12,  // .stage_num_col
+    10,  // .stage_num_row
+    // 1,  // .log_scale
     fwd_shift_adst_dct_32,            // .shift
     fwd_stage_range_col_adst_dct_32,  // .stage_range_col
     fwd_stage_range_row_adst_dct_32,  // .stage_range_row
diff --git a/vp10/common/vp10_inv_txfm2d.c b/vp10/common/vp10_inv_txfm2d.c
index d9f713c..a1ad4b8 100644
--- a/vp10/common/vp10_inv_txfm2d.c
+++ b/vp10/common/vp10_inv_txfm2d.c
@@ -11,9 +11,6 @@
 #include "vp10/common/vp10_txfm.h"
 #include "vp10/common/vp10_inv_txfm1d.h"
 
-typedef void (*TxfmFunc)(const int32_t *input, int32_t *output,
-                         const int8_t *cos_bit, const int8_t *stage_range);
-
 static inline TxfmFunc inv_txfm_type_to_func(TXFM_TYPE txfm_type) {
   switch (txfm_type) {
     case TXFM_TYPE_DCT4:
diff --git a/vp10/common/vp10_inv_txfm2d_cfg.h b/vp10/common/vp10_inv_txfm2d_cfg.h
index ee965ba..9199068 100644
--- a/vp10/common/vp10_inv_txfm2d_cfg.h
+++ b/vp10/common/vp10_inv_txfm2d_cfg.h
@@ -12,16 +12,17 @@
 #define VP10_INV_TXFM2D_CFG_H_
 #include "vp10/common/vp10_inv_txfm1d.h"
 //  ---------------- config inv_dct_dct_4 ----------------
-static const int8_t inv_shift_dct_dct_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_dct_dct_4[4] = {17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_dct_4[4] = {16, 16, 16, 16};
-static const int8_t inv_cos_bit_col_dct_dct_4[4] = {15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_dct_4[4] = {15, 15, 15, 15};
+static const int8_t inv_shift_dct_dct_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_dct_dct_4[4] = {18, 18, 17, 17};
+static const int8_t inv_stage_range_row_dct_dct_4[4] = {18, 18, 18, 18};
+static const int8_t inv_cos_bit_col_dct_dct_4[4] = {13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_4[4] = {13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_4 = {
-    4,                              // .txfm_size
-    4,                              // .stage_num_col
-    4,                              // .stage_num_row
+    4,  // .txfm_size
+    4,  // .stage_num_col
+    4,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_dct_4,            // .shift
     inv_stage_range_col_dct_dct_4,  // .stage_range_col
     inv_stage_range_row_dct_dct_4,  // .stage_range_row
@@ -32,15 +33,16 @@
 
 //  ---------------- config inv_dct_dct_8 ----------------
 static const int8_t inv_shift_dct_dct_8[2] = {0, -5};
-static const int8_t inv_stage_range_col_dct_dct_8[6] = {17, 17, 17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_dct_8[6] = {17, 17, 17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_dct_dct_8[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_dct_8[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_stage_range_col_dct_dct_8[6] = {19, 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_8[6] = {19, 19, 19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_8[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_8 = {
-    8,                              // .txfm_size
-    6,                              // .stage_num_col
-    6,                              // .stage_num_row
+    8,  // .txfm_size
+    6,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_dct_8,            // .shift
     inv_stage_range_col_dct_dct_8,  // .stage_range_col
     inv_stage_range_row_dct_dct_8,  // .stage_range_row
@@ -50,20 +52,21 @@
     TXFM_TYPE_DCT8};                // .txfm_type_row
 
 //  ---------------- config inv_dct_dct_16 ----------------
-static const int8_t inv_shift_dct_dct_16[2] = {0, -6};
-static const int8_t inv_stage_range_col_dct_dct_16[8] = {18, 18, 18, 18,
-                                                         18, 18, 17, 17};
-static const int8_t inv_stage_range_row_dct_dct_16[8] = {18, 18, 18, 18,
-                                                         18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_dct_dct_16[8] = {14, 14, 14, 14,
-                                                     14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_dct_16[8] = {14, 14, 14, 14,
-                                                     14, 14, 14, 14};
+static const int8_t inv_shift_dct_dct_16[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_dct_16[8] = {19, 19, 19, 19,
+                                                         19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_16[8] = {20, 20, 20, 20,
+                                                         20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_dct_16[8] = {13, 13, 13, 13,
+                                                     13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_16[8] = {12, 12, 12, 12,
+                                                     12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_16 = {
-    16,                              // .txfm_size
-    8,                               // .stage_num_col
-    8,                               // .stage_num_row
+    16,  // .txfm_size
+    8,   // .stage_num_col
+    8,   // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_dct_16,            // .shift
     inv_stage_range_col_dct_dct_16,  // .stage_range_col
     inv_stage_range_row_dct_dct_16,  // .stage_range_row
@@ -73,20 +76,21 @@
     TXFM_TYPE_DCT16};                // .txfm_type_row
 
 //  ---------------- config inv_dct_dct_32 ----------------
-static const int8_t inv_shift_dct_dct_32[2] = {-1, -6};
-static const int8_t inv_stage_range_col_dct_dct_32[10] = {18, 18, 18, 18, 18,
-                                                          18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_dct_dct_32[10] = {19, 19, 19, 19, 19,
-                                                          19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_dct_dct_32[10] = {14, 14, 14, 14, 14,
-                                                      14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_dct_32[10] = {13, 13, 13, 13, 13,
+static const int8_t inv_shift_dct_dct_32[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_dct_32[10] = {19, 19, 19, 19, 19,
+                                                          19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_dct_dct_32[10] = {20, 20, 20, 20, 20,
+                                                          20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_dct_32[10] = {13, 13, 13, 13, 13,
                                                       13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_dct_32[10] = {12, 12, 12, 12, 12,
+                                                      12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_dct_32 = {
-    32,                              // .txfm_size
-    10,                              // .stage_num_col
-    10,                              // .stage_num_row
+    32,  // .txfm_size
+    10,  // .stage_num_col
+    10,  // .stage_num_row
+    // 1,  // .log_scale
     inv_shift_dct_dct_32,            // .shift
     inv_stage_range_col_dct_dct_32,  // .stage_range_col
     inv_stage_range_row_dct_dct_32,  // .stage_range_row
@@ -102,7 +106,7 @@
 static const int8_t inv_stage_range_row_dct_dct_64[12] = {
     20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
 static const int8_t inv_cos_bit_col_dct_dct_64[12] = {13, 13, 13, 13, 13, 13,
-                                                      13, 13, 13, 13, 13, 14};
+                                                      13, 13, 13, 13, 13, 13};
 static const int8_t inv_cos_bit_row_dct_dct_64[12] = {12, 12, 12, 12, 12, 12,
                                                       12, 12, 12, 12, 12, 12};
 
@@ -119,17 +123,18 @@
     TXFM_TYPE_DCT64};                // .txfm_type_row
 
 //  ---------------- config inv_dct_adst_4 ----------------
-static const int8_t inv_shift_dct_adst_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_dct_adst_4[4] = {17, 17, 16, 16};
-static const int8_t inv_stage_range_row_dct_adst_4[6] = {16, 16, 16,
-                                                         16, 16, 16};
-static const int8_t inv_cos_bit_col_dct_adst_4[4] = {15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_shift_dct_adst_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_dct_adst_4[4] = {18, 18, 17, 17};
+static const int8_t inv_stage_range_row_dct_adst_4[6] = {18, 18, 18,
+                                                         18, 18, 18};
+static const int8_t inv_cos_bit_col_dct_adst_4[4] = {13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_4[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_4 = {
-    4,                               // .txfm_size
-    4,                               // .stage_num_col
-    6,                               // .stage_num_row
+    4,  // .txfm_size
+    4,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_adst_4,            // .shift
     inv_stage_range_col_dct_adst_4,  // .stage_range_col
     inv_stage_range_row_dct_adst_4,  // .stage_range_row
@@ -139,19 +144,20 @@
     TXFM_TYPE_ADST4};                // .txfm_type_row
 
 //  ---------------- config inv_dct_adst_8 ----------------
-static const int8_t inv_shift_dct_adst_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_dct_adst_8[6] = {16, 16, 16,
-                                                         16, 15, 15};
-static const int8_t inv_stage_range_row_dct_adst_8[8] = {17, 17, 17, 17,
-                                                         17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_dct_adst_8[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_dct_adst_8[8] = {15, 15, 15, 15,
-                                                     15, 15, 15, 15};
+static const int8_t inv_shift_dct_adst_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_dct_adst_8[6] = {19, 19, 19,
+                                                         19, 18, 18};
+static const int8_t inv_stage_range_row_dct_adst_8[8] = {19, 19, 19, 19,
+                                                         19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_dct_adst_8[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_8[8] = {13, 13, 13, 13,
+                                                     13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_8 = {
-    8,                               // .txfm_size
-    6,                               // .stage_num_col
-    8,                               // .stage_num_row
+    8,  // .txfm_size
+    6,  // .stage_num_col
+    8,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_adst_8,            // .shift
     inv_stage_range_col_dct_adst_8,  // .stage_range_col
     inv_stage_range_row_dct_adst_8,  // .stage_range_row
@@ -161,20 +167,21 @@
     TXFM_TYPE_ADST8};                // .txfm_type_row
 
 //  ---------------- config inv_dct_adst_16 ----------------
-static const int8_t inv_shift_dct_adst_16[2] = {1, -7};
+static const int8_t inv_shift_dct_adst_16[2] = {-1, -5};
 static const int8_t inv_stage_range_col_dct_adst_16[8] = {19, 19, 19, 19,
                                                           19, 19, 18, 18};
-static const int8_t inv_stage_range_row_dct_adst_16[10] = {18, 18, 18, 18, 18,
-                                                           18, 18, 18, 18, 18};
+static const int8_t inv_stage_range_row_dct_adst_16[10] = {20, 20, 20, 20, 20,
+                                                           20, 20, 20, 20, 20};
 static const int8_t inv_cos_bit_col_dct_adst_16[8] = {13, 13, 13, 13,
-                                                      13, 13, 13, 14};
-static const int8_t inv_cos_bit_row_dct_adst_16[10] = {14, 14, 14, 14, 14,
-                                                       14, 14, 14, 14, 14};
+                                                      13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_16[10] = {12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_16 = {
-    16,                               // .txfm_size
-    8,                                // .stage_num_col
-    10,                               // .stage_num_row
+    16,  // .txfm_size
+    8,   // .stage_num_col
+    10,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_dct_adst_16,            // .shift
     inv_stage_range_col_dct_adst_16,  // .stage_range_col
     inv_stage_range_row_dct_adst_16,  // .stage_range_row
@@ -184,20 +191,21 @@
     TXFM_TYPE_ADST16};                // .txfm_type_row
 
 //  ---------------- config inv_dct_adst_32 ----------------
-static const int8_t inv_shift_dct_adst_32[2] = {-1, -6};
-static const int8_t inv_stage_range_col_dct_adst_32[10] = {18, 18, 18, 18, 18,
-                                                           18, 18, 18, 17, 17};
+static const int8_t inv_shift_dct_adst_32[2] = {-1, -5};
+static const int8_t inv_stage_range_col_dct_adst_32[10] = {19, 19, 19, 19, 19,
+                                                           19, 19, 19, 18, 18};
 static const int8_t inv_stage_range_row_dct_adst_32[12] = {
-    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_dct_adst_32[10] = {14, 14, 14, 14, 14,
-                                                       14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_dct_adst_32[12] = {13, 13, 13, 13, 13, 13,
-                                                       13, 13, 13, 13, 13, 13};
+    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_dct_adst_32[10] = {13, 13, 13, 13, 13,
+                                                       13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_dct_adst_32[12] = {12, 12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_dct_adst_32 = {
-    32,                               // .txfm_size
-    10,                               // .stage_num_col
-    12,                               // .stage_num_row
+    32,  // .txfm_size
+    10,  // .stage_num_col
+    12,  // .stage_num_row
+    // 1,  // .log_scale
     inv_shift_dct_adst_32,            // .shift
     inv_stage_range_col_dct_adst_32,  // .stage_range_col
     inv_stage_range_row_dct_adst_32,  // .stage_range_row
@@ -208,17 +216,18 @@
 
 //  ---------------- config inv_adst_adst_4 ----------------
 static const int8_t inv_shift_adst_adst_4[2] = {0, -4};
-static const int8_t inv_stage_range_col_adst_adst_4[6] = {16, 16, 16,
-                                                          16, 15, 15};
-static const int8_t inv_stage_range_row_adst_adst_4[6] = {16, 16, 16,
-                                                          16, 16, 16};
-static const int8_t inv_cos_bit_col_adst_adst_4[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_adst_4[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_stage_range_col_adst_adst_4[6] = {18, 18, 18,
+                                                          18, 17, 17};
+static const int8_t inv_stage_range_row_adst_adst_4[6] = {18, 18, 18,
+                                                          18, 18, 18};
+static const int8_t inv_cos_bit_col_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_4[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_4 = {
-    4,                                // .txfm_size
-    6,                                // .stage_num_col
-    6,                                // .stage_num_row
+    4,  // .txfm_size
+    6,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_adst_4,            // .shift
     inv_stage_range_col_adst_adst_4,  // .stage_range_col
     inv_stage_range_row_adst_adst_4,  // .stage_range_row
@@ -228,20 +237,21 @@
     TXFM_TYPE_ADST4};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_adst_8 ----------------
-static const int8_t inv_shift_adst_adst_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_adst_adst_8[8] = {16, 16, 16, 16,
-                                                          16, 16, 15, 15};
-static const int8_t inv_stage_range_row_adst_adst_8[8] = {17, 17, 17, 17,
-                                                          17, 17, 17, 17};
-static const int8_t inv_cos_bit_col_adst_adst_8[8] = {15, 15, 15, 15,
-                                                      15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_adst_8[8] = {15, 15, 15, 15,
-                                                      15, 15, 15, 15};
+static const int8_t inv_shift_adst_adst_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_adst_adst_8[8] = {19, 19, 19, 19,
+                                                          19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_adst_8[8] = {19, 19, 19, 19,
+                                                          19, 19, 19, 19};
+static const int8_t inv_cos_bit_col_adst_adst_8[8] = {13, 13, 13, 13,
+                                                      13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_8[8] = {13, 13, 13, 13,
+                                                      13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_8 = {
-    8,                                // .txfm_size
-    8,                                // .stage_num_col
-    8,                                // .stage_num_row
+    8,  // .txfm_size
+    8,  // .stage_num_col
+    8,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_adst_8,            // .shift
     inv_stage_range_col_adst_adst_8,  // .stage_range_col
     inv_stage_range_row_adst_adst_8,  // .stage_range_row
@@ -251,20 +261,21 @@
     TXFM_TYPE_ADST8};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_adst_16 ----------------
-static const int8_t inv_shift_adst_adst_16[2] = {0, -6};
-static const int8_t inv_stage_range_col_adst_adst_16[10] = {18, 18, 18, 18, 18,
-                                                            18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_adst_adst_16[10] = {18, 18, 18, 18, 18,
-                                                            18, 18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_adst_adst_16[10] = {14, 14, 14, 14, 14,
-                                                        14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_adst_16[10] = {14, 14, 14, 14, 14,
-                                                        14, 14, 14, 14, 14};
+static const int8_t inv_shift_adst_adst_16[2] = {-1, -5};
+static const int8_t inv_stage_range_col_adst_adst_16[10] = {19, 19, 19, 19, 19,
+                                                            19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_adst_16[10] = {20, 20, 20, 20, 20,
+                                                            20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_adst_16[10] = {13, 13, 13, 13, 13,
+                                                        13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_16[10] = {12, 12, 12, 12, 12,
+                                                        12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_16 = {
-    16,                                // .txfm_size
-    10,                                // .stage_num_col
-    10,                                // .stage_num_row
+    16,  // .txfm_size
+    10,  // .stage_num_col
+    10,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_adst_16,            // .shift
     inv_stage_range_col_adst_adst_16,  // .stage_range_col
     inv_stage_range_row_adst_adst_16,  // .stage_range_row
@@ -274,20 +285,21 @@
     TXFM_TYPE_ADST16};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_adst_32 ----------------
-static const int8_t inv_shift_adst_adst_32[2] = {-1, -6};
+static const int8_t inv_shift_adst_adst_32[2] = {-1, -5};
 static const int8_t inv_stage_range_col_adst_adst_32[12] = {
-    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17};
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18};
 static const int8_t inv_stage_range_row_adst_adst_32[12] = {
-    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_adst_adst_32[12] = {14, 14, 14, 14, 14, 14,
-                                                        14, 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_adst_32[12] = {13, 13, 13, 13, 13, 13,
+    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_adst_32[12] = {13, 13, 13, 13, 13, 13,
                                                         13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_adst_32[12] = {12, 12, 12, 12, 12, 12,
+                                                        12, 12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_adst_32 = {
-    32,                                // .txfm_size
-    12,                                // .stage_num_col
-    12,                                // .stage_num_row
+    32,  // .txfm_size
+    12,  // .stage_num_col
+    12,  // .stage_num_row
+    // 1,  // .log_scale
     inv_shift_adst_adst_32,            // .shift
     inv_stage_range_col_adst_adst_32,  // .stage_range_col
     inv_stage_range_row_adst_adst_32,  // .stage_range_row
@@ -297,17 +309,18 @@
     TXFM_TYPE_ADST32};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_dct_4 ----------------
-static const int8_t inv_shift_adst_dct_4[2] = {1, -5};
-static const int8_t inv_stage_range_col_adst_dct_4[6] = {17, 17, 17,
-                                                         17, 16, 16};
-static const int8_t inv_stage_range_row_adst_dct_4[4] = {16, 16, 16, 16};
-static const int8_t inv_cos_bit_col_adst_dct_4[6] = {15, 15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_4[4] = {15, 15, 15, 15};
+static const int8_t inv_shift_adst_dct_4[2] = {0, -4};
+static const int8_t inv_stage_range_col_adst_dct_4[6] = {18, 18, 18,
+                                                         18, 17, 17};
+static const int8_t inv_stage_range_row_adst_dct_4[4] = {18, 18, 18, 18};
+static const int8_t inv_cos_bit_col_adst_dct_4[6] = {13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_4[4] = {13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_4 = {
-    4,                               // .txfm_size
-    6,                               // .stage_num_col
-    4,                               // .stage_num_row
+    4,  // .txfm_size
+    6,  // .stage_num_col
+    4,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_dct_4,            // .shift
     inv_stage_range_col_adst_dct_4,  // .stage_range_col
     inv_stage_range_row_adst_dct_4,  // .stage_range_row
@@ -317,19 +330,20 @@
     TXFM_TYPE_DCT4};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_dct_8 ----------------
-static const int8_t inv_shift_adst_dct_8[2] = {-1, -4};
-static const int8_t inv_stage_range_col_adst_dct_8[8] = {16, 16, 16, 16,
-                                                         16, 16, 15, 15};
-static const int8_t inv_stage_range_row_adst_dct_8[6] = {17, 17, 17,
-                                                         17, 17, 17};
-static const int8_t inv_cos_bit_col_adst_dct_8[8] = {15, 15, 15, 15,
-                                                     15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_8[6] = {15, 15, 15, 15, 15, 15};
+static const int8_t inv_shift_adst_dct_8[2] = {0, -5};
+static const int8_t inv_stage_range_col_adst_dct_8[8] = {19, 19, 19, 19,
+                                                         19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_8[6] = {19, 19, 19,
+                                                         19, 19, 19};
+static const int8_t inv_cos_bit_col_adst_dct_8[8] = {13, 13, 13, 13,
+                                                     13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_8[6] = {13, 13, 13, 13, 13, 13};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_8 = {
-    8,                               // .txfm_size
-    8,                               // .stage_num_col
-    6,                               // .stage_num_row
+    8,  // .txfm_size
+    8,  // .stage_num_col
+    6,  // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_dct_8,            // .shift
     inv_stage_range_col_adst_dct_8,  // .stage_range_col
     inv_stage_range_row_adst_dct_8,  // .stage_range_row
@@ -340,19 +354,20 @@
 
 //  ---------------- config inv_adst_dct_16 ----------------
 static const int8_t inv_shift_adst_dct_16[2] = {-1, -5};
-static const int8_t inv_stage_range_col_adst_dct_16[10] = {17, 17, 17, 17, 17,
-                                                           17, 17, 17, 16, 16};
-static const int8_t inv_stage_range_row_adst_dct_16[8] = {18, 18, 18, 18,
-                                                          18, 18, 18, 18};
-static const int8_t inv_cos_bit_col_adst_dct_16[10] = {15, 15, 15, 15, 15,
-                                                       15, 15, 15, 15, 15};
-static const int8_t inv_cos_bit_row_adst_dct_16[8] = {14, 14, 14, 14,
-                                                      14, 14, 14, 14};
+static const int8_t inv_stage_range_col_adst_dct_16[10] = {19, 19, 19, 19, 19,
+                                                           19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_16[8] = {20, 20, 20, 20,
+                                                          20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_dct_16[10] = {13, 13, 13, 13, 13,
+                                                       13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_16[8] = {12, 12, 12, 12,
+                                                      12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_16 = {
-    16,                               // .txfm_size
-    10,                               // .stage_num_col
-    8,                                // .stage_num_row
+    16,  // .txfm_size
+    10,  // .stage_num_col
+    8,   // .stage_num_row
+    // 0,  // .log_scale
     inv_shift_adst_dct_16,            // .shift
     inv_stage_range_col_adst_dct_16,  // .stage_range_col
     inv_stage_range_row_adst_dct_16,  // .stage_range_row
@@ -362,20 +377,21 @@
     TXFM_TYPE_DCT16};                 // .txfm_type_row
 
 //  ---------------- config inv_adst_dct_32 ----------------
-static const int8_t inv_shift_adst_dct_32[2] = {-1, -6};
+static const int8_t inv_shift_adst_dct_32[2] = {-1, -5};
 static const int8_t inv_stage_range_col_adst_dct_32[12] = {
-    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17};
-static const int8_t inv_stage_range_row_adst_dct_32[10] = {19, 19, 19, 19, 19,
-                                                           19, 19, 19, 19, 19};
-static const int8_t inv_cos_bit_col_adst_dct_32[12] = {14, 14, 14, 14, 14, 14,
-                                                       14, 14, 14, 14, 14, 15};
-static const int8_t inv_cos_bit_row_adst_dct_32[10] = {13, 13, 13, 13, 13,
-                                                       13, 13, 13, 13, 13};
+    19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18};
+static const int8_t inv_stage_range_row_adst_dct_32[10] = {20, 20, 20, 20, 20,
+                                                           20, 20, 20, 20, 20};
+static const int8_t inv_cos_bit_col_adst_dct_32[12] = {13, 13, 13, 13, 13, 13,
+                                                       13, 13, 13, 13, 13, 13};
+static const int8_t inv_cos_bit_row_adst_dct_32[10] = {12, 12, 12, 12, 12,
+                                                       12, 12, 12, 12, 12};
 
 static const TXFM_2D_CFG inv_txfm_2d_cfg_adst_dct_32 = {
-    32,                               // .txfm_size
-    12,                               // .stage_num_col
-    10,                               // .stage_num_row
+    32,  // .txfm_size
+    12,  // .stage_num_col
+    10,  // .stage_num_row
+    // 1,  // .log_scale
     inv_shift_adst_dct_32,            // .shift
     inv_stage_range_col_adst_dct_32,  // .stage_range_col
     inv_stage_range_row_adst_dct_32,  // .stage_range_row
diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c
index 17e7401..0e51b15 100644
--- a/vp10/decoder/decodeframe.c
+++ b/vp10/decoder/decodeframe.c
@@ -291,7 +291,7 @@
                                              token_tab,
 #endif  // CONFIG_ANS
                                              plane, sc, col, row, tx_size,
-                                             r, mbmi->segment_id);
+                                             tx_type, r, mbmi->segment_id);
     inverse_transform_block(xd, plane, tx_type, tx_size,
                             dst, pd->dst.stride, eob);
   }
@@ -327,7 +327,7 @@
     const scan_order *sc = get_scan(tx_size, tx_type, 1);
     const int eob = vp10_decode_block_tokens(xd, plane, sc,
                                              blk_col, blk_row, tx_size,
-                                             r, mbmi->segment_id);
+                                             tx_type, r, mbmi->segment_id);
     inverse_transform_block(xd, plane, tx_type, tx_size,
         &pd->dst.buf[4 * blk_row * pd->dst.stride + 4 * blk_col],
         pd->dst.stride, eob);
@@ -373,7 +373,8 @@
 #if CONFIG_ANS
                                            token_tab,
 #endif
-                                           plane, sc, col, row, tx_size, r,
+                                           plane, sc, col, row,
+                                           tx_size, tx_type, r,
                                            mbmi->segment_id);
 
   inverse_transform_block(xd, plane, tx_type, tx_size,
diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c
index b52696d..3c91a66 100644
--- a/vp10/decoder/decodemv.c
+++ b/vp10/decoder/decodemv.c
@@ -64,10 +64,10 @@
 
 #if CONFIG_EXT_INTER
 static INTERINTRA_MODE read_interintra_mode(VP10_COMMON *cm, MACROBLOCKD *xd,
-                                            vpx_reader *r, int size_group) {
+                                            vp10_reader *r, int size_group) {
   const INTERINTRA_MODE ii_mode =
-      (INTERINTRA_MODE)vpx_read_tree(r, vp10_interintra_mode_tree,
-                                     cm->fc->interintra_mode_prob[size_group]);
+      (INTERINTRA_MODE)vp10_read_tree(r, vp10_interintra_mode_tree,
+                                      cm->fc->interintra_mode_prob[size_group]);
   FRAME_COUNTS *counts = xd->counts;
   if (counts)
     ++counts->interintra_mode[size_group][ii_mode];
@@ -1230,14 +1230,6 @@
                       mi_row, mi_col, fpm_sync, (void *)pbi, inter_mode_ctx);
   }
 
-#if CONFIG_OBMC
-  mbmi->obmc = 0;
-#if CONFIG_SUPERTX
-  if (!supertx_enabled)
-#endif  // CONFIG_SUPERTX
-    mbmi->obmc = read_is_obmc_block(cm, xd, r);
-#endif  // CONFIG_OBMC
-
 #if CONFIG_REF_MV
 #if CONFIG_EXT_INTER
   if (is_compound)
@@ -1293,7 +1285,6 @@
   if (mbmi->ref_mv_idx > 0) {
     int_mv cur_mv =
         xd->ref_mv_stack[mbmi->ref_frame[0]][1 + mbmi->ref_mv_idx].this_mv;
-    lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
     nearmv[0] = cur_mv;
   }
 
@@ -1310,15 +1301,11 @@
 #else
     if (xd->ref_mv_count[ref_frame_type] == 1 && mbmi->mode == NEARESTMV) {
 #endif  // CONFIG_EXT_INTER
-      int i;
 #if CONFIG_EXT_INTER
       if (mbmi->mode == NEAREST_NEARESTMV) {
 #endif  // CONFIG_EXT_INTER
       nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
       nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
-
-      for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
-        lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
 #if CONFIG_EXT_INTER
       } else if (mbmi->mode == NEAREST_NEWMV || mbmi->mode == NEAREST_NEARMV) {
         nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
@@ -1344,17 +1331,11 @@
     }
 #else
     if (xd->ref_mv_count[ref_frame_type] > 1) {
-      int i;
       int ref_mv_idx = 1 + mbmi->ref_mv_idx;
       nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
       nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
       nearmv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv;
       nearmv[1] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
-
-      for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
-        lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
-        lower_mv_precision(&nearmv[i].as_mv, allow_hp);
-      }
     }
 #endif  // CONFIG_EXT_INTER
   }
@@ -1495,7 +1476,6 @@
             xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].this_mv :
             xd->ref_mv_stack[ref_frame_type][mbmi->ref_mv_idx].comp_mv;
         clamp_mv_ref(&ref_mv[ref].as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
-        lower_mv_precision(&ref_mv[ref].as_mv, allow_hp);
       }
 #endif
       nearestmv[ref] = ref_mv[ref];
@@ -1516,18 +1496,14 @@
   }
 
 #if CONFIG_EXT_INTER
-    mbmi->use_wedge_interintra = 0;
-    mbmi->use_wedge_interinter = 0;
+  mbmi->use_wedge_interintra = 0;
   if (cm->reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
-      !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif  // CONFIG_OBMC
 #if CONFIG_SUPERTX
       !supertx_enabled &&
 #endif
       is_interintra_allowed(mbmi)) {
     const int bsize_group = size_group_lookup[bsize];
-    const int interintra = vpx_read(r, cm->fc->interintra_prob[bsize_group]);
+    const int interintra = vp10_read(r, cm->fc->interintra_prob[bsize_group]);
     if (xd->counts)
       xd->counts->interintra[bsize_group][interintra]++;
     assert(mbmi->ref_frame[1] == NONE);
@@ -1557,6 +1533,21 @@
       }
     }
   }
+#endif  // CONFIG_EXT_INTER
+
+#if CONFIG_OBMC
+  mbmi->obmc = 0;
+#if CONFIG_SUPERTX
+  if (!supertx_enabled)
+#endif  // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+    if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif  // CONFIG_EXT_INTER
+    mbmi->obmc = read_is_obmc_block(cm, xd, r);
+#endif  // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
+  mbmi->use_wedge_interinter = 0;
   if (cm->reference_mode != SINGLE_REFERENCE &&
       is_inter_compound_mode(mbmi->mode) &&
 #if CONFIG_OBMC
diff --git a/vp10/decoder/detokenize.c b/vp10/decoder/detokenize.c
index 58cd9e6..def3d7a 100644
--- a/vp10/decoder/detokenize.c
+++ b/vp10/decoder/detokenize.c
@@ -47,7 +47,8 @@
 
 static int decode_coefs(const MACROBLOCKD *xd,
                         PLANE_TYPE type,
-                        tran_low_t *dqcoeff, TX_SIZE tx_size, const int16_t *dq,
+                        tran_low_t *dqcoeff, TX_SIZE tx_size, TX_TYPE tx_type,
+                        const int16_t *dq,
                         int ctx, const int16_t *scan, const int16_t *nb,
                         vp10_reader *r) {
   FRAME_COUNTS *counts = xd->counts;
@@ -111,7 +112,7 @@
   cat6_prob = vp10_cat6_prob;
 #endif
 
-  dq_shift = get_tx_scale(xd, 0, tx_size);
+  dq_shift = get_tx_scale(xd, tx_type, tx_size);
 
   while (c < max_eob) {
     int val = -1;
@@ -222,6 +223,7 @@
                             const rans_dec_lut *const token_tab,
                             PLANE_TYPE type,
                             tran_low_t *dqcoeff, TX_SIZE tx_size,
+                            TX_TYPE tx_type,
                             const int16_t *dq,
                             int ctx, const int16_t *scan, const int16_t *nb,
                             struct AnsDecoder *const ans) {
@@ -247,7 +249,7 @@
   const uint8_t *cat5_prob;
   const uint8_t *cat6_prob;
 
-  dq_shift = get_tx_scale(xd, 0, tx_size);
+  dq_shift = get_tx_scale(xd, tx_type, tx_size);
 
   if (counts) {
     coef_counts = counts->coef[tx_size][type][ref];
@@ -462,6 +464,7 @@
                              int plane, const scan_order *sc,
                              int x, int y,
                              TX_SIZE tx_size,
+                             TX_TYPE tx_type,
 #if CONFIG_ANS
                              struct AnsDecoder *const r,
 #else
@@ -474,11 +477,11 @@
                                                pd->left_context + y);
 #if !CONFIG_ANS
   const int eob = decode_coefs(xd, pd->plane_type,
-                               pd->dqcoeff, tx_size,
+                               pd->dqcoeff, tx_size, tx_type,
                                dequant, ctx, sc->scan, sc->neighbors, r);
 #else
   const int eob = decode_coefs_ans(xd, token_tab, pd->plane_type,
-                                   pd->dqcoeff, tx_size,
+                                   pd->dqcoeff, tx_size, tx_type,
                                    dequant, ctx, sc->scan, sc->neighbors, r);
 #endif  // !CONFIG_ANS
   dec_set_contexts(xd, pd, tx_size, eob > 0, x, y);
diff --git a/vp10/decoder/detokenize.h b/vp10/decoder/detokenize.h
index 4688d0a..a19d90f 100644
--- a/vp10/decoder/detokenize.h
+++ b/vp10/decoder/detokenize.h
@@ -29,6 +29,7 @@
                              int plane, const scan_order *sc,
                              int x, int y,
                              TX_SIZE tx_size,
+                             TX_TYPE tx_type,
 #if CONFIG_ANS
                              struct AnsDecoder *const r,
 #else
diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c
index 3687073..b7bd6fc 100644
--- a/vp10/encoder/bitstream.c
+++ b/vp10/encoder/bitstream.c
@@ -145,7 +145,7 @@
 }
 
 #if CONFIG_EXT_INTER
-static void write_interintra_mode(vpx_writer *w, INTERINTRA_MODE mode,
+static void write_interintra_mode(vp10_writer *w, INTERINTRA_MODE mode,
                                   const vpx_prob *probs) {
   vp10_write_token(w, vp10_interintra_mode_tree, probs,
                    &interintra_mode_encodings[mode]);
@@ -1115,14 +1115,6 @@
     int16_t mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]];
     write_ref_frames(cm, xd, w);
 
-#if CONFIG_OBMC
-#if CONFIG_SUPERTX
-    if (!supertx_enabled)
-#endif  // CONFIG_SUPERTX
-      if (is_obmc_allowed(mbmi))
-        vp10_write(w, mbmi->obmc, cm->fc->obmc_prob[bsize]);
-#endif  // CONFIG_OBMC
-
 #if CONFIG_REF_MV
 #if CONFIG_EXT_INTER
     if (is_compound)
@@ -1286,24 +1278,21 @@
 
 #if CONFIG_EXT_INTER
     if (cpi->common.reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
-        !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif  // CONFIG_OBMC
 #if CONFIG_SUPERTX
         !supertx_enabled &&
 #endif  // CONFIG_SUPERTX
         is_interintra_allowed(mbmi)) {
       const int interintra = mbmi->ref_frame[1] == INTRA_FRAME;
       const int bsize_group = size_group_lookup[bsize];
-      vpx_write(w, interintra, cm->fc->interintra_prob[bsize_group]);
+      vp10_write(w, interintra, cm->fc->interintra_prob[bsize_group]);
       if (interintra) {
         write_interintra_mode(
             w, mbmi->interintra_mode,
             cm->fc->interintra_mode_prob[bsize_group]);
         assert(mbmi->interintra_mode == mbmi->interintra_uv_mode);
         if (is_interintra_wedge_used(bsize)) {
-          vpx_write(w, mbmi->use_wedge_interintra,
-                    cm->fc->wedge_interintra_prob[bsize]);
+          vp10_write(w, mbmi->use_wedge_interintra,
+                     cm->fc->wedge_interintra_prob[bsize]);
           if (mbmi->use_wedge_interintra) {
             vp10_write_literal(w, mbmi->interintra_wedge_index,
                               get_wedge_bits(bsize));
@@ -1311,14 +1300,28 @@
         }
       }
     }
+#endif  // CONFIG_EXT_INTER
+
+#if CONFIG_OBMC
+#if CONFIG_SUPERTX
+    if (!supertx_enabled)
+#endif  // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+      if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif  // CONFIG_EXT_INTER
+      if (is_obmc_allowed(mbmi))
+        vp10_write(w, mbmi->obmc, cm->fc->obmc_prob[bsize]);
+#endif  // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
     if (cpi->common.reference_mode != SINGLE_REFERENCE &&
         is_inter_compound_mode(mbmi->mode) &&
 #if CONFIG_OBMC
         !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
 #endif  // CONFIG_OBMC
         is_interinter_wedge_used(bsize)) {
-      vpx_write(w, mbmi->use_wedge_interinter,
-                cm->fc->wedge_interinter_prob[bsize]);
+      vp10_write(w, mbmi->use_wedge_interinter,
+                 cm->fc->wedge_interinter_prob[bsize]);
       if (mbmi->use_wedge_interinter)
         vp10_write_literal(w, mbmi->interinter_wedge_index,
                           get_wedge_bits(bsize));
diff --git a/vp10/encoder/block.h b/vp10/encoder/block.h
index 2e8af98..095aee5 100644
--- a/vp10/encoder/block.h
+++ b/vp10/encoder/block.h
@@ -104,6 +104,7 @@
   int mv_best_ref_index[MAX_REF_FRAMES];
   unsigned int max_mv_context[MAX_REF_FRAMES];
   unsigned int source_variance;
+  unsigned int recon_variance;
 #if CONFIG_OBMC
   unsigned int pred_variance;
 #endif  // CONFIG_OBMC
diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c
index 06463c1..45505f1 100644
--- a/vp10/encoder/encodeframe.c
+++ b/vp10/encoder/encodeframe.c
@@ -1067,7 +1067,6 @@
           x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv :
           x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv;
       clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
-      lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
       x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv;
       mbmi->pred_mv[i] = this_mv;
     }
@@ -1890,21 +1889,8 @@
 #endif  // CONFIG_EXT_REFS
         }
 
-#if CONFIG_OBMC
-#if CONFIG_SUPERTX
-        if (!supertx_enabled)
-#endif  // CONFIG_SUPERTX
-          if (is_obmc_allowed(mbmi))
-            counts->obmc[mbmi->sb_type][mbmi->obmc]++;
-#endif  // CONFIG_OBMC
-      }
-    }
-
 #if CONFIG_EXT_INTER
     if (cm->reference_mode != COMPOUND_REFERENCE &&
-#if CONFIG_OBMC
-        !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif
 #if CONFIG_SUPERTX
         !supertx_enabled &&
 #endif
@@ -1919,16 +1905,32 @@
         counts->interintra[bsize_group][0]++;
       }
     }
-    if (cm->reference_mode != SINGLE_REFERENCE &&
-        is_inter_compound_mode(mbmi->mode) &&
-#if CONFIG_OBMC
-        !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
-#endif  // CONFIG_OBMC
-        is_interinter_wedge_used(bsize)) {
-      counts->wedge_interinter[bsize][mbmi->use_wedge_interinter]++;
-    }
 #endif  // CONFIG_EXT_INTER
 
+#if CONFIG_OBMC
+#if CONFIG_SUPERTX
+        if (!supertx_enabled)
+#endif  // CONFIG_SUPERTX
+#if CONFIG_EXT_INTER
+        if (mbmi->ref_frame[1] != INTRA_FRAME)
+#endif  // CONFIG_EXT_INTER
+          if (is_obmc_allowed(mbmi))
+            counts->obmc[mbmi->sb_type][mbmi->obmc]++;
+#endif  // CONFIG_OBMC
+
+#if CONFIG_EXT_INTER
+        if (cm->reference_mode != SINGLE_REFERENCE &&
+            is_inter_compound_mode(mbmi->mode) &&
+#if CONFIG_OBMC
+            !(is_obmc_allowed(mbmi) && mbmi->obmc) &&
+#endif  // CONFIG_OBMC
+            is_interinter_wedge_used(bsize)) {
+          counts->wedge_interinter[bsize][mbmi->use_wedge_interinter]++;
+        }
+#endif  // CONFIG_EXT_INTER
+      }
+    }
+
     if (inter_block &&
         !segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
       int16_t mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]];
diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c
index 7776c22..2d51114 100644
--- a/vp10/encoder/encoder.c
+++ b/vp10/encoder/encoder.c
@@ -4107,14 +4107,14 @@
   const int last2_is_last =
       map[cpi->lst_fb_idxes[1]] == map[cpi->lst_fb_idxes[0]];
   const int gld_is_last2 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[1]];
-  const int alt_is_last2 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[1]];
+  const int last2_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[1]];
 
   const int last3_is_last =
       map[cpi->lst_fb_idxes[2]] == map[cpi->lst_fb_idxes[0]];
   const int last3_is_last2 =
       map[cpi->lst_fb_idxes[2]] == map[cpi->lst_fb_idxes[1]];
   const int gld_is_last3 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[2]];
-  const int alt_is_last3 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[2]];
+  const int last3_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[2]];
 
   const int last4_is_last =
       map[cpi->lst_fb_idxes[3]] == map[cpi->lst_fb_idxes[0]];
@@ -4123,21 +4123,16 @@
   const int last4_is_last3 =
       map[cpi->lst_fb_idxes[3]] == map[cpi->lst_fb_idxes[2]];
   const int gld_is_last4 = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idxes[3]];
-  const int alt_is_last4 = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[3]];
+  const int last4_is_alt = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idxes[3]];
 #else
   const int gld_is_last = map[cpi->gld_fb_idx] == map[cpi->lst_fb_idx];
   const int alt_is_last = map[cpi->alt_fb_idx] == map[cpi->lst_fb_idx];
 #endif  // CONFIG_EXT_REFS
   const int gld_is_alt = map[cpi->gld_fb_idx] == map[cpi->alt_fb_idx];
 
-  int flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
-#if CONFIG_EXT_REFS
-  flags |= VP9_LAST2_FLAG;
-  flags |= VP9_LAST3_FLAG;
-  flags |= VP9_LAST4_FLAG;
-#endif  // CONFIG_EXT_REFS
+  int flags = VP9_REFFRAME_ALL;
 
-  if (gld_is_last)
+  if (gld_is_alt || gld_is_last)
     flags &= ~VP9_GOLD_FLAG;
 
   if (cpi->rc.frames_till_gf_update_due == INT_MAX)
@@ -4146,24 +4141,18 @@
   if (alt_is_last)
     flags &= ~VP9_ALT_FLAG;
 
-  if (gld_is_alt)
-    flags &= ~VP9_ALT_FLAG;
-
 #if CONFIG_EXT_REFS
-  if (last4_is_last || last4_is_last2 || last4_is_last3)
+  if (last4_is_alt || last4_is_last || last4_is_last2 || last4_is_last3)
     flags &= ~VP9_LAST4_FLAG;
 
-  if (last3_is_last || last3_is_last2)
+  if (last3_is_alt || last3_is_last || last3_is_last2)
     flags &= ~VP9_LAST3_FLAG;
 
-  if (last2_is_last)
+  if (last2_is_alt || last2_is_last)
     flags &= ~VP9_LAST2_FLAG;
 
   if (gld_is_last4 || gld_is_last3 || gld_is_last2)
     flags &= ~VP9_GOLD_FLAG;
-
-  if (alt_is_last4 || alt_is_last3 || alt_is_last2)
-    flags &= ~VP9_ALT_FLAG;
 #endif  // CONFIG_EXT_REFS
 
   return flags;
diff --git a/vp10/encoder/hybrid_fwd_txfm.c b/vp10/encoder/hybrid_fwd_txfm.c
index 3ccaf39..b192164 100644
--- a/vp10/encoder/hybrid_fwd_txfm.c
+++ b/vp10/encoder/hybrid_fwd_txfm.c
@@ -195,17 +195,20 @@
 
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10) {
-        vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
-                            &fwd_txfm_2d_cfg_dct_dct_4, bd);
-      } else {
-        vp10_highbd_fht4x4(src_diff, coeff, diff_stride, tx_type);
-      }
+      vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_dct_dct_4, bd);
       break;
     case ADST_DCT:
+      vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_adst_dct_4, bd);
+      break;
     case DCT_ADST:
+      vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_dct_adst_4, bd);
+      break;
     case ADST_ADST:
-      vp10_highbd_fht4x4_c(src_diff, coeff, diff_stride, tx_type);
+      vp10_fwd_txfm2d_4x4(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_adst_adst_4, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -239,18 +242,20 @@
   (void)fwd_txfm_opt;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10) {
-        vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
-                            &fwd_txfm_2d_cfg_dct_dct_8, bd);
-        break;
-      }
+      vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_dct_dct_8, bd);
+      break;
     case ADST_DCT:
+      vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_adst_dct_8, bd);
+      break;
     case DCT_ADST:
+      vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_dct_adst_8, bd);
+      break;
     case ADST_ADST:
-      if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
-        vp10_highbd_fht8x8(src_diff, coeff, diff_stride, tx_type);
-      else  // FWD_TXFM_OPT_DC
-        vpx_highbd_fdct8x8_1(src_diff, coeff, diff_stride);
+      vp10_fwd_txfm2d_8x8(src_diff, coeff, diff_stride,
+                          &fwd_txfm_2d_cfg_adst_adst_8, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -285,18 +290,20 @@
   (void)fwd_txfm_opt;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10) {
-        vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
-                              &fwd_txfm_2d_cfg_dct_dct_16, bd);
-        break;
-      }
+      vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+                            &fwd_txfm_2d_cfg_dct_dct_16, bd);
+      break;
     case ADST_DCT:
+      vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+                            &fwd_txfm_2d_cfg_adst_dct_16, bd);
+      break;
     case DCT_ADST:
+      vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+                            &fwd_txfm_2d_cfg_dct_adst_16, bd);
+      break;
     case ADST_ADST:
-      if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
-        vp10_highbd_fht16x16(src_diff, coeff, diff_stride, tx_type);
-      else  // FWD_TXFM_OPT_DC
-        vpx_highbd_fdct16x16_1(src_diff, coeff, diff_stride);
+      vp10_fwd_txfm2d_16x16(src_diff, coeff, diff_stride,
+                            &fwd_txfm_2d_cfg_adst_adst_16, bd);
       break;
 #if CONFIG_EXT_TX
     case FLIPADST_DCT:
@@ -329,18 +336,12 @@
                                   tran_low_t *coeff, int diff_stride,
                                   TX_TYPE tx_type, FWD_TXFM_OPT fwd_txfm_opt,
                                   const int bd) {
-  (void)bd;
+  (void)rd_transform;
+  (void)fwd_txfm_opt;
   switch (tx_type) {
     case DCT_DCT:
-      if (bd == BITDEPTH_10) {
-        vp10_fwd_txfm2d_32x32(src_diff, coeff, diff_stride,
-                              &fwd_txfm_2d_cfg_dct_dct_32, bd);
-      } else {
-        if (fwd_txfm_opt == FWD_TXFM_OPT_NORMAL)
-          highbd_fdct32x32(rd_transform, src_diff, coeff, diff_stride);
-        else  // FWD_TXFM_OPT_DC
-          vpx_highbd_fdct32x32_1(src_diff, coeff, diff_stride);
-      }
+      vp10_fwd_txfm2d_32x32(src_diff, coeff, diff_stride,
+                            &fwd_txfm_2d_cfg_dct_dct_32, bd);
       break;
 #if CONFIG_EXT_TX
     case ADST_DCT:
diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c
index 05cb75c..e7762a5 100644
--- a/vp10/encoder/rdopt.c
+++ b/vp10/encoder/rdopt.c
@@ -81,12 +81,6 @@
 #define MIN_EARLY_TERM_INDEX    3
 #define NEW_MV_DISCOUNT_FACTOR  8
 
-#if CONFIG_EXT_TX
-const double ext_tx_th = 0.99;
-#else
-const double ext_tx_th = 0.99;
-#endif
-
 const double ADST_FLIP_SVM[8] = {-6.6623, -2.8062, -3.2531, 3.1671,  // vert
                                  -7.7051, -3.2234, -3.6193, 3.4533};  // horz
 
@@ -1001,7 +995,8 @@
     const struct macroblock_plane *const p = &x->plane[plane];
     const struct macroblockd_plane *const pd = &xd->plane[plane];
     int64_t this_sse;
-    int shift = (MAX_TX_SCALE - get_tx_scale(xd, 0, tx_size)) * 2;
+    int tx_type = get_tx_type(pd->plane_type, xd, block, tx_size);
+    int shift = (MAX_TX_SCALE - get_tx_scale(xd, tx_type, tx_size)) * 2;
     tran_low_t *const coeff = BLOCK_OFFSET(p->coeff, block);
     tran_low_t *const dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
 #if CONFIG_VP9_HIGHBITDEPTH
@@ -1175,7 +1170,9 @@
         const int64_t orig_sse = (int64_t)coeff[0] * coeff[0];
         const int64_t resd_sse = coeff[0] - dqcoeff[0];
         int64_t dc_correct = orig_sse - resd_sse * resd_sse;
-        int shift = (MAX_TX_SCALE - get_tx_scale(xd, 0, tx_size)) * 2;
+        const struct macroblockd_plane *const pd = &xd->plane[plane];
+        TX_TYPE tx_type = get_tx_type(pd->plane_type, xd, block, tx_size);
+        int shift = (MAX_TX_SCALE - get_tx_scale(xd, tx_type, tx_size)) * 2;
 #if CONFIG_VP9_HIGHBITDEPTH
         dc_correct >>= ((xd->bd - 8) * 2);
 #endif
@@ -1435,7 +1432,9 @@
   last_rd = INT64_MAX;
   for (n = start_tx; n >= end_tx; --n) {
     if (FIXED_TX_TYPE && tx_type != get_default_tx_type(0, xd, 0, n))
-        continue;
+      continue;
+    if (max_tx_size == TX_32X32 && n == TX_4X4)
+      continue;
 #if CONFIG_EXT_TX
     ext_tx_set = get_ext_tx_set(n, bs, is_inter);
     if (is_inter) {
@@ -1562,7 +1561,7 @@
       if (is_inter_block(mbmi) && !xd->lossless[mbmi->segment_id] && !s)
         this_rd = VPXMIN(this_rd, RDCOST(x->rdmult, x->rddiv, s1, psse));
 
-      if (this_rd < ((best_tx_type == DCT_DCT) ? ext_tx_th : 1) * best_rd) {
+      if (this_rd < best_rd) {
         best_rd = this_rd;
         best_tx_type = mbmi->tx_type;
       }
@@ -1597,7 +1596,7 @@
       if (is_inter && !xd->lossless[mbmi->segment_id] && !s)
         this_rd = VPXMIN(this_rd, RDCOST(x->rdmult, x->rddiv, s1, psse));
 
-      if (this_rd < ((best_tx_type == DCT_DCT) ? ext_tx_th : 1) * best_rd) {
+      if (this_rd < best_rd) {
         best_rd = this_rd;
         best_tx_type = mbmi->tx_type;
       }
@@ -1658,9 +1657,13 @@
   *psse       = INT64_MAX;
 
   for (tx_type = DCT_DCT; tx_type < TX_TYPES; ++tx_type) {
+#if CONFIG_REF_MV
+    if (tx_type != DCT_DCT && is_inter && mbmi->ref_mv_idx > 0)
+      continue;
+#endif
     rd = choose_tx_size_fix_type(cpi, x, &r, &d, &s, &sse, ref_best_rd, bs,
                                  tx_type, prune);
-    if (rd < (is_inter && best_tx_type == DCT_DCT ? ext_tx_th : 1) * best_rd) {
+    if (rd < best_rd) {
       best_rd = rd;
       *distortion = d;
       *rate       = r;
@@ -1678,12 +1681,6 @@
   if (mbmi->tx_size >= TX_32X32)
     assert(mbmi->tx_type == DCT_DCT);
 #endif
-
-  txfm_rd_in_plane(x,
-                   cpi,
-                   &r, &d, &s,
-                   &sse, ref_best_rd, 0, bs, best_tx,
-                   cpi->sf.use_fast_coef_costing);
 }
 
 static void super_block_yrd(VP10_COMP *cpi, MACROBLOCK *x, int *rate,
@@ -3282,7 +3279,7 @@
     rd = select_tx_size_fix_type(cpi, x, &this_rate, &this_dist, &this_skip,
                                  &this_sse, bsize, ref_best_rd, tx_type);
 
-    if (rd < (is_inter && best_tx_type == DCT_DCT ? ext_tx_th : 1) * best_rd) {
+    if (rd < best_rd) {
       best_rd = rd;
       *distortion = this_dist;
       *rate       = this_rate;
@@ -4951,7 +4948,7 @@
 #if CONFIG_REF_MV
         run_mv_search = 2;
 #if !CONFIG_EXT_INTER
-        if (filter_idx > 0) {
+        if (filter_idx > 0 && this_mode == NEWMV) {
           BEST_SEG_INFO* ref_bsi = bsi_buf;
           SEG_RDSTAT *ref_rdstat = &ref_bsi->rdstat[i][mode_idx];
 
@@ -5345,6 +5342,24 @@
                   ref_bsi->rdstat[i + 2][mode_idx].eobs;
 
             if (bsi->rdstat[i][mode_idx].brdcost < best_rd) {
+#if CONFIG_REF_MV
+              // If the NEWMV mode is using the same motion vector as the
+              // NEARESTMV mode, skip the rest rate-distortion calculations
+              // and use the inferred motion vector modes.
+              if (this_mode == NEWMV) {
+                if (has_second_rf) {
+                  if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+                          bsi->ref_mv[0]->as_int &&
+                      bsi->rdstat[i][mode_idx].mvs[1].as_int ==
+                          bsi->ref_mv[1]->as_int)
+                    continue;
+                } else {
+                  if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+                      bsi->ref_mv[0]->as_int)
+                    continue;
+                }
+              }
+#endif
               mode_selected = this_mode;
               best_rd = bsi->rdstat[i][mode_idx].brdcost;
             }
@@ -5375,6 +5390,24 @@
         }
 
         if (bsi->rdstat[i][mode_idx].brdcost < best_rd) {
+#if CONFIG_REF_MV
+          // If the NEWMV mode is using the same motion vector as the
+          // NEARESTMV mode, skip the rest rate-distortion calculations
+          // and use the inferred motion vector modes.
+          if (this_mode == NEWMV) {
+            if (has_second_rf) {
+              if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+                      bsi->ref_mv[0]->as_int &&
+                  bsi->rdstat[i][mode_idx].mvs[1].as_int ==
+                      bsi->ref_mv[1]->as_int)
+                continue;
+            } else {
+              if (bsi->rdstat[i][mode_idx].mvs[0].as_int ==
+                  bsi->ref_mv[0]->as_int)
+                continue;
+            }
+          }
+#endif
           mode_selected = this_mode;
           best_rd = bsi->rdstat[i][mode_idx].brdcost;
         }
@@ -6241,6 +6274,10 @@
   int64_t best_distortion = INT64_MAX;
   unsigned int best_pred_var = UINT_MAX;
   MB_MODE_INFO best_mbmi;
+#if CONFIG_EXT_INTER
+  int rate2_bmc_nocoeff;
+  MB_MODE_INFO best_bmc_mbmi;
+#endif  // CONFIG_EXT_INTER
 #endif  // CONFIG_OBMC
 
   int pred_exists = 0;
@@ -6271,9 +6308,6 @@
   assert(!is_comp_interintra_pred || is_interintra_allowed(mbmi));
 #endif  // CONFIG_EXT_INTER
 
-#if CONFIG_OBMC
-  tmp_rd = 0;
-#endif  // CONFIG_OBMC
 #if CONFIG_REF_MV
 #if CONFIG_EXT_INTER
   if (is_comp_pred)
@@ -6414,7 +6448,6 @@
       cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
 
       for (i = 0; i < 2; ++i) {
-        lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
         clamp_mv2(&cur_mv[i].as_mv, xd);
         if (mv_check_bounds(x, &cur_mv[i].as_mv))
           return INT64_MAX;
@@ -6476,7 +6509,6 @@
       cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
 
       for (i = 0; i < 2; ++i) {
-        lower_mv_precision(&cur_mv[i].as_mv, cm->allow_high_precision_mv);
         clamp_mv2(&cur_mv[i].as_mv, xd);
         if (mv_check_bounds(x, &cur_mv[i].as_mv))
           return INT64_MAX;
@@ -6636,6 +6668,12 @@
   rs = cm->interp_filter == SWITCHABLE ? vp10_get_switchable_rate(cpi, xd) : 0;
 
 #if CONFIG_EXT_INTER
+#if CONFIG_OBMC
+  best_bmc_mbmi = *mbmi;
+  rate2_bmc_nocoeff = *rate2;
+  if (cm->interp_filter == SWITCHABLE)
+    rate2_bmc_nocoeff += rs;
+#endif  // CONFIG_OBMC
   if (is_comp_pred && is_interinter_wedge_used(bsize)) {
     int wedge_index, best_wedge_index = WEDGE_NONE, rs;
     int rate_sum;
@@ -6748,7 +6786,6 @@
           xd, bsize, mi_row, mi_col, 1, preds1, strides);
       for (wedge_index = 0; wedge_index < wedge_types; ++wedge_index) {
         mbmi->interinter_wedge_index = wedge_index;
-        // vp10_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
         vp10_build_wedge_inter_predictor_from_buf(xd, bsize, mi_row, mi_col,
                                                   preds0, strides,
                                                   preds1, strides);
@@ -6767,12 +6804,8 @@
         mbmi->use_wedge_interinter = 0;
       }
     }
-#if CONFIG_OBMC
-    if (mbmi->use_wedge_interinter)
-      allow_obmc = 0;
-#endif  // CONFIG_OBMC
     if (ref_best_rd < INT64_MAX &&
-        VPXMIN(best_rd_wedge, best_rd_nowedge) / 2 > ref_best_rd)
+        VPXMIN(best_rd_wedge, best_rd_nowedge) / 3 > ref_best_rd)
       return INT64_MAX;
 
     pred_exists = 0;
@@ -7072,7 +7105,6 @@
   memcpy(x->skip_txfm, skip_txfm, sizeof(skip_txfm));
   memcpy(x->bsse, bsse, sizeof(bsse));
 
-
 #if CONFIG_OBMC
   best_rd = INT64_MAX;
   for (mbmi->obmc = 0; mbmi->obmc <= allow_obmc; mbmi->obmc++) {
@@ -7080,6 +7112,12 @@
     int tmp_rate;
 
     if (mbmi->obmc) {
+#if CONFIG_EXT_INTER
+      *mbmi = best_bmc_mbmi;
+      assert(!mbmi->use_wedge_interinter);
+      vp10_build_inter_predictors_sb(xd, mi_row, mi_col, bsize);
+      mbmi->obmc = 1;
+#endif  // CONFIG_EXT_INTER
       vp10_build_obmc_inter_prediction(cm, xd, mi_row, mi_col, 0,
                                        NULL, NULL,
                                        dst_buf1, dst_stride1,
@@ -7099,13 +7137,16 @@
     x->pred_variance =
         vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
 #endif  // CONFIG_VP9_HIGHBITDEPTH
-
     x->skip = 0;
 
+#if CONFIG_EXT_INTER
+    *rate2 = mbmi->obmc ? rate2_bmc_nocoeff : rate2_nocoeff;
+#else
     *rate2 = rate2_nocoeff;
-    *distortion = 0;
+#endif  // CONFIG_EXT_INTER
     if (allow_obmc)
       *rate2 += cpi->obmc_cost[bsize][mbmi->obmc];
+    *distortion = 0;
 #endif  // CONFIG_OBMC
   if (!skip_txfm_sb) {
     int skippable_y, skippable_uv;
@@ -7260,6 +7301,20 @@
   if (!is_comp_pred)
     single_skippable[this_mode][refs[0]] = *skippable;
 
+#if CONFIG_VP9_HIGHBITDEPTH
+  if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+    x->recon_variance =
+      vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst,
+                                          bsize, xd->bd);
+  } else {
+    x->recon_variance =
+      vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+  }
+#else
+  x->recon_variance =
+    vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+#endif  // CONFIG_VP9_HIGHBITDEPTH
+
   restore_dst_buf(xd, orig_dst, orig_dst_stride);
   return 0;  // The rate-distortion cost will be re-calculated by caller.
 }
@@ -7320,17 +7375,14 @@
 #define LOW_VAR_THRESH 16
 #define VLOW_ADJ_MAX 25
 #define VHIGH_ADJ_MAX 8
-static void rd_variance_adjustment(VP10_COMP *cpi,
-                                   MACROBLOCK *x,
-                                   BLOCK_SIZE bsize,
+static void rd_variance_adjustment(MACROBLOCK *x,
                                    int64_t *this_rd,
                                    MV_REFERENCE_FRAME ref_frame,
 #if CONFIG_OBMC
                                    int is_pred_var_available,
 #endif  // CONFIG_OBMC
                                    unsigned int source_variance) {
-  MACROBLOCKD *const xd = &x->e_mbd;
-  unsigned int recon_variance;
+  unsigned int recon_variance = x->recon_variance;
   unsigned int absvar_diff = 0;
   int64_t var_error = 0;
   int64_t var_factor = 0;
@@ -7339,24 +7391,8 @@
     return;
 
 #if CONFIG_OBMC
-  if (is_pred_var_available) {
+  if (is_pred_var_available)
     recon_variance = x->pred_variance;
-  } else {
-#endif  // CONFIG_OBMC
-#if CONFIG_VP9_HIGHBITDEPTH
-  if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
-    recon_variance =
-      vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize, xd->bd);
-  } else {
-    recon_variance =
-      vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
-  }
-#else
-  recon_variance =
-    vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
-#endif  // CONFIG_VP9_HIGHBITDEPTH
-#if CONFIG_OBMC
-  }
 #endif  // CONFIG_OBMC
 
   if ((source_variance + recon_variance) > LOW_VAR_THRESH) {
@@ -7780,6 +7816,7 @@
 
   if (cpi->rc.is_src_frame_alt_ref) {
     if (sf->alt_ref_search_fp) {
+      assert(cpi->ref_frame_flags & flag_list[ALTREF_FRAME]);
       mode_skip_mask[ALTREF_FRAME] = 0;
       ref_frame_skip_mask[0] = ~(1 << ALTREF_FRAME);
       ref_frame_skip_mask[1] = SECOND_REF_FRAME_MASK;
@@ -8206,6 +8243,20 @@
       if (this_mode != DC_PRED && this_mode != TM_PRED)
         rate2 += intra_cost_penalty;
       distortion2 = distortion_y + distortion_uv;
+      vp10_encode_intra_block_plane(x, bsize, 0);
+#if CONFIG_VP9_HIGHBITDEPTH
+      if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
+        x->recon_variance =
+          vp10_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst,
+                                              bsize, xd->bd);
+      } else {
+        x->recon_variance =
+          vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+      }
+#else
+      x->recon_variance =
+        vp10_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize);
+#endif  // CONFIG_VP9_HIGHBITDEPTH
     } else {
 #if CONFIG_REF_MV
       int_mv backup_ref_mv[2];
@@ -8243,7 +8294,6 @@
               mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv :
               mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
           clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
-          lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
           mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
         }
       }
@@ -8333,13 +8383,11 @@
                 mbmi_ext->ref_mv_stack[ref_frame_type]
                                       [mbmi->ref_mv_idx].comp_mv;
             clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd);
-            lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv);
             mbmi_ext->ref_mvs[mbmi->ref_frame[ref]][0] = this_mv;
           }
 
           cur_mv = mbmi_ext->ref_mv_stack[ref_frame]
                                  [mbmi->ref_mv_idx + idx_offset].this_mv;
-          lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
           clamp_mv2(&cur_mv.as_mv, xd);
 
           if (!mv_check_bounds(x, &cur_mv.as_mv)) {
@@ -8465,6 +8513,9 @@
 #if CONFIG_EXT_INTER
     rate2 += compmode_interintra_cost;
     if (cm->reference_mode != SINGLE_REFERENCE && comp_pred)
+#if CONFIG_OBMC
+      if (mbmi->obmc == 0)
+#endif  // CONFIG_OBMC
       rate2 += compmode_wedge_cost;
 #endif  // CONFIG_EXT_INTER
 
@@ -8519,7 +8570,7 @@
 
     // Apply an adjustment to the rd value based on the similarity of the
     // source variance and reconstructed variance.
-    rd_variance_adjustment(cpi, x, bsize, &this_rd, ref_frame,
+    rd_variance_adjustment(x, &this_rd, ref_frame,
 #if CONFIG_OBMC
                            is_inter_block(mbmi),
 #endif  // CONFIG_OBMC
@@ -8571,7 +8622,7 @@
         *returnrate_nocoef -= vp10_cost_bit(vp10_get_intra_inter_prob(cm, xd),
                                             mbmi->ref_frame[0] != INTRA_FRAME);
 #if CONFIG_OBMC
-        if (is_neighbor_overlappable(mbmi) && is_obmc_allowed(mbmi))
+        if (is_inter_block(mbmi) && is_obmc_allowed(mbmi))
           *returnrate_nocoef -= cpi->obmc_cost[bsize][mbmi->obmc];
 #endif  // CONFIG_OBMC
 #endif  // CONFIG_SUPERTX
@@ -8785,7 +8836,6 @@
 
       for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
         int_mv cur_mv = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
-        lower_mv_precision(&cur_mv.as_mv, cm->allow_high_precision_mv);
         if (cur_mv.as_int == best_mbmode.mv[0].as_int) {
           best_mbmode.mode = NEARMV;
           best_mbmode.ref_mv_idx = i;
@@ -8798,7 +8848,6 @@
         best_mbmode.mode = ZEROMV;
     } else {
       int i;
-      const int allow_hp = cm->allow_high_precision_mv;
       int_mv nearestmv[2] = { frame_mv[NEARESTMV][refs[0]],
                               frame_mv[NEARESTMV][refs[1]] };
       int_mv nearmv[2] = { frame_mv[NEARMV][refs[0]],
@@ -8816,8 +8865,6 @@
       for (i = 0; i <= ref_set && ref_set != INT_MAX; ++i) {
         nearmv[0] = mbmi_ext->ref_mv_stack[rf_type][i + 1].this_mv;
         nearmv[1] = mbmi_ext->ref_mv_stack[rf_type][i + 1].comp_mv;
-        lower_mv_precision(&nearmv[0].as_mv, allow_hp);
-        lower_mv_precision(&nearmv[1].as_mv, allow_hp);
 
         if (nearmv[0].as_int == best_mbmode.mv[0].as_int &&
             nearmv[1].as_int == best_mbmode.mv[1].as_int) {
@@ -8832,11 +8879,6 @@
         nearestmv[1] = mbmi_ext->ref_mv_stack[rf_type][0].comp_mv;
       }
 
-      for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
-        lower_mv_precision(&nearestmv[i].as_mv, allow_hp);
-        lower_mv_precision(&nearmv[i].as_mv, allow_hp);
-      }
-
       if (nearestmv[0].as_int == best_mbmode.mv[0].as_int &&
           nearestmv[1].as_int == best_mbmode.mv[1].as_int)
 #if CONFIG_EXT_INTER
diff --git a/vp10/encoder/resize.c b/vp10/encoder/resize.c
index e339fa3..353e513 100644
--- a/vp10/encoder/resize.c
+++ b/vp10/encoder/resize.c
@@ -445,7 +445,7 @@
                              int length,
                              uint8_t *output,
                              int olength,
-                             uint8_t *buf) {
+                             uint8_t *otmp) {
   int steps;
   if (length == olength) {
     memcpy(output, input, sizeof(output[0]) * length);
@@ -456,16 +456,10 @@
   if (steps > 0) {
     int s;
     uint8_t *out = NULL;
-    uint8_t *tmpbuf = NULL;
-    uint8_t *otmp, *otmp2;
+    uint8_t *otmp2;
     int filteredlength = length;
-    if (!tmpbuf) {
-      tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
-      if (tmpbuf == NULL) return;
-      otmp = tmpbuf;
-    } else {
-      otmp = buf;
-    }
+
+    assert(otmp != NULL);
     otmp2 = otmp + get_down2_length(length, 1);
     for (s = 0; s < steps; ++s) {
       const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -483,8 +477,6 @@
     if (filteredlength != olength) {
       interpolate(out, filteredlength, output, olength);
     }
-    if (tmpbuf)
-      free(tmpbuf);
   } else {
     interpolate(input, length, output, olength);
   }
@@ -520,8 +512,11 @@
   uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
   uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
                                       (width < height ? height : width));
-  uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
-  if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+  uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * height);
+  uint8_t *arrbuf2 = (uint8_t *)malloc(sizeof(uint8_t) * height2);
+  if (intbuf == NULL || tmpbuf == NULL ||
+      arrbuf == NULL || arrbuf2 == NULL)
+    goto Error;
   assert(width > 0);
   assert(height > 0);
   assert(width2 > 0);
@@ -531,14 +526,15 @@
                         intbuf + width2 * i, width2, tmpbuf);
   for (i = 0; i < width2; ++i) {
     fill_col_to_arr(intbuf + i, width2, height, arrbuf);
-    resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
-    fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
+    resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf);
+    fill_arr_to_col(output + i, out_stride, height2, arrbuf2);
   }
 
  Error:
   free(intbuf);
   free(tmpbuf);
   free(arrbuf);
+  free(arrbuf2);
 }
 
 #if CONFIG_VP9_HIGHBITDEPTH
@@ -741,7 +737,7 @@
                                     int length,
                                     uint16_t *output,
                                     int olength,
-                                    uint16_t *buf,
+                                    uint16_t *otmp,
                                     int bd) {
   int steps;
   if (length == olength) {
@@ -753,16 +749,10 @@
   if (steps > 0) {
     int s;
     uint16_t *out = NULL;
-    uint16_t *tmpbuf = NULL;
-    uint16_t *otmp, *otmp2;
+    uint16_t *otmp2;
     int filteredlength = length;
-    if (!tmpbuf) {
-      tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
-      if (tmpbuf == NULL) return;
-      otmp = tmpbuf;
-    } else {
-      otmp = buf;
-    }
+
+    assert(otmp != NULL);
     otmp2 = otmp + get_down2_length(length, 1);
     for (s = 0; s < steps; ++s) {
       const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -780,8 +770,6 @@
     if (filteredlength != olength) {
       highbd_interpolate(out, filteredlength, output, olength, bd);
     }
-    if (tmpbuf)
-      free(tmpbuf);
   } else {
     highbd_interpolate(input, length, output, olength, bd);
   }
@@ -820,24 +808,27 @@
   uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
   uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
                                         (width < height ? height : width));
-  uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
-  if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+  uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * height);
+  uint16_t *arrbuf2 = (uint16_t *)malloc(sizeof(uint16_t) * height2);
+  if (intbuf == NULL || tmpbuf == NULL ||
+      arrbuf == NULL || arrbuf2 == NULL) goto Error;
   for (i = 0; i < height; ++i) {
     highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
                             intbuf + width2 * i, width2, tmpbuf, bd);
   }
   for (i = 0; i < width2; ++i) {
     highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
-    highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
+    highbd_resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf,
                             bd);
     highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
-                           arrbuf + height);
+                           arrbuf2);
   }
 
  Error:
   free(intbuf);
   free(tmpbuf);
   free(arrbuf);
+  free(arrbuf2);
 }
 #endif  // CONFIG_VP9_HIGHBITDEPTH
 
diff --git a/vp10/encoder/x86/highbd_fwd_txfm_sse4.c b/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
index 5fa4fc8..16323b3 100644
--- a/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
+++ b/vp10/encoder/x86/highbd_fwd_txfm_sse4.c
@@ -13,15 +13,14 @@
 
 #include "./vp10_rtcd.h"
 #include "./vpx_config.h"
+#include "vp10/common/vp10_fwd_txfm2d_cfg.h"
+#include "vp10/common/vp10_txfm.h"
 #include "vpx_dsp/txfm_common.h"
 #include "vpx_ports/mem.h"
 
 static INLINE void load_buffer_4x4(const int16_t *input, __m128i *in,
-                                   int stride, int flipud, int fliplr) {
-  const __m128i k__nonzero_bias_a = _mm_setr_epi32(0, 1, 1, 1);
-  const __m128i k__nonzero_bias_b = _mm_setr_epi32(1, 0, 0, 0);
-  __m128i mask;
-
+                                   int stride, int flipud, int fliplr,
+                                   int shift) {
   if (!flipud) {
     in[0] = _mm_loadl_epi64((const __m128i *)(input + 0 * stride));
     in[1] = _mm_loadl_epi64((const __m128i *)(input + 1 * stride));
@@ -46,120 +45,73 @@
   in[2] = _mm_cvtepi16_epi32(in[2]);
   in[3] = _mm_cvtepi16_epi32(in[3]);
 
-  in[0] = _mm_slli_epi32(in[0], 4);
-  in[1] = _mm_slli_epi32(in[1], 4);
-  in[2] = _mm_slli_epi32(in[2], 4);
-  in[3] = _mm_slli_epi32(in[3], 4);
-
-  mask = _mm_cmpeq_epi32(in[0], k__nonzero_bias_a);
-  in[0] = _mm_add_epi32(in[0], mask);
-  in[0] = _mm_add_epi32(in[0], k__nonzero_bias_b);
+  in[0] = _mm_slli_epi32(in[0], shift);
+  in[1] = _mm_slli_epi32(in[1], shift);
+  in[2] = _mm_slli_epi32(in[2], shift);
+  in[3] = _mm_slli_epi32(in[3], shift);
 }
 
-static void fdct4x4_sse4_1(__m128i *in) {
-  const __m128i k__cospi_p16_p16 = _mm_set1_epi64x(cospi_16_64);
-  const __m128i k__cospi_m16_m16 = _mm_set1_epi64x(-cospi_16_64);
-  const __m128i k__cospi_p08_p08 = _mm_set1_epi64x(cospi_8_64);
-  const __m128i k__cospi_m08_m08 = _mm_set1_epi64x(-cospi_8_64);
-  const __m128i k__cospi_p24_p24 = _mm_set1_epi64x(cospi_24_64);
-  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi64x(DCT_CONST_ROUNDING);
-
-  __m128i s[8];
+// We only use stage-2 bit;
+// shift[0] is used in load_buffer_4x4()
+// shift[1] is used in txfm_func_col()
+// shift[2] is used in txfm_func_row()
+static void fdct4x4_sse4_1(__m128i *in, int bit) {
+  const int32_t *cospi = cospi_arr[bit - cos_bit_min];
+  const __m128i cospi32 = _mm_set1_epi32(cospi[32]);
+  const __m128i cospi48 = _mm_set1_epi32(cospi[48]);
+  const __m128i cospi16 = _mm_set1_epi32(cospi[16]);
+  const __m128i rnding = _mm_set1_epi32(1 << (bit - 1));
+  __m128i s0, s1, s2, s3;
   __m128i u0, u1, u2, u3;
-  __m128i v0, v1, v2, v3, v4, v5, v6, v7;
+  __m128i v0, v1, v2, v3;
 
-  s[0] = _mm_add_epi32(in[0], in[3]);
-  s[1] = _mm_add_epi32(in[1], in[2]);
-  s[2] = _mm_sub_epi32(in[1], in[2]);
-  s[3] = _mm_sub_epi32(in[0], in[3]);
+  s0 = _mm_add_epi32(in[0], in[3]);
+  s1 = _mm_add_epi32(in[1], in[2]);
+  s2 = _mm_sub_epi32(in[1], in[2]);
+  s3 = _mm_sub_epi32(in[0], in[3]);
 
-  v0 = _mm_cvtepi32_epi64(s[0]);  // s01 s00
-  v1 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[0], s[0]));  // s03 s02
-  v2 = _mm_cvtepi32_epi64(s[1]);  // s11 s10
-  v3 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[1], s[1]));  // s13 s12
-  v4 = _mm_cvtepi32_epi64(s[2]);  // s21 s20
-  v5 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[2], s[2]));  // s23 s22
-  v6 = _mm_cvtepi32_epi64(s[3]);  // s31 s30
-  v7 = _mm_cvtepi32_epi64(_mm_unpackhi_epi64(s[3], s[3]));  // s33 s32
+  // btf_32_sse4_1_type0(cospi32, cospi32, s[01], u[02], bit);
+  u0 = _mm_mullo_epi32(s0, cospi32);
+  u1 = _mm_mullo_epi32(s1, cospi32);
+  u2 = _mm_add_epi32(u0, u1);
+  v0 = _mm_sub_epi32(u0, u1);
 
-  u0 = _mm_mul_epi32(v0, k__cospi_p16_p16);
-  u1 = _mm_mul_epi32(v1, k__cospi_p16_p16);
-  u2 = _mm_mul_epi32(v2, k__cospi_p16_p16);
-  u3 = _mm_mul_epi32(v3, k__cospi_p16_p16);
+  u3 = _mm_add_epi32(u2, rnding);
+  v1 = _mm_add_epi32(v0, rnding);
 
-  s[0] = _mm_add_epi64(u0, u2);  // y10 y00
-  s[1] = _mm_add_epi64(u1, u3);  // y30 y20
+  u0 = _mm_srai_epi32(u3, bit);
+  u2 = _mm_srai_epi32(v1, bit);
 
-  u2 = _mm_mul_epi32(v2, k__cospi_m16_m16);
-  u3 = _mm_mul_epi32(v3, k__cospi_m16_m16);
+  // btf_32_sse4_1_type1(cospi48, cospi16, s[23], u[13], bit);
+  v0 = _mm_mullo_epi32(s2, cospi48);
+  v1 = _mm_mullo_epi32(s3, cospi16);
+  v2 = _mm_add_epi32(v0, v1);
 
-  s[2] = _mm_add_epi64(u0, u2);  // y12 y02
-  s[3] = _mm_add_epi64(u1, u3);  // y32 y22
+  v3 = _mm_add_epi32(v2, rnding);
+  u1 = _mm_srai_epi32(v3, bit);
 
-  u0 = _mm_mul_epi32(v6, k__cospi_p08_p08);
-  u1 = _mm_mul_epi32(v5, k__cospi_p24_p24);
-  u2 = _mm_mul_epi32(v4, k__cospi_p24_p24);
-  u3 = _mm_mul_epi32(v7, k__cospi_p08_p08);
+  v0 = _mm_mullo_epi32(s2, cospi16);
+  v1 = _mm_mullo_epi32(s3, cospi48);
+  v2 = _mm_sub_epi32(v1, v0);
 
-  s[4] = _mm_add_epi64(u0, u2);  // y11 y01
-  s[5] = _mm_add_epi64(u1, u3);  // y31 y21
+  v3 = _mm_add_epi32(v2, rnding);
+  u3 = _mm_srai_epi32(v3, bit);
 
-  u0 = _mm_mul_epi32(v4, k__cospi_m08_m08);
-  u1 = _mm_mul_epi32(v5, k__cospi_m08_m08);
-  u2 = _mm_mul_epi32(v6, k__cospi_p24_p24);
-  u3 = _mm_mul_epi32(v7, k__cospi_p24_p24);
+  // Note: shift[1] and shift[2] are zeros
 
-  s[6] = _mm_add_epi64(u0, u2);  // y13 y03
-  s[7] = _mm_add_epi64(u1, u3);  // y33 y23
+  // Transpose 4x4 32-bit
+  v0 = _mm_unpacklo_epi32(u0, u1);
+  v1 = _mm_unpackhi_epi32(u0, u1);
+  v2 = _mm_unpacklo_epi32(u2, u3);
+  v3 = _mm_unpackhi_epi32(u2, u3);
 
-  s[0] = _mm_add_epi64(s[0], k__DCT_CONST_ROUNDING);
-  s[1] = _mm_add_epi64(s[1], k__DCT_CONST_ROUNDING);
-  s[2] = _mm_add_epi64(s[2], k__DCT_CONST_ROUNDING);
-  s[3] = _mm_add_epi64(s[3], k__DCT_CONST_ROUNDING);
-  s[4] = _mm_add_epi64(s[4], k__DCT_CONST_ROUNDING);
-  s[5] = _mm_add_epi64(s[5], k__DCT_CONST_ROUNDING);
-  s[6] = _mm_add_epi64(s[6], k__DCT_CONST_ROUNDING);
-  s[7] = _mm_add_epi64(s[7], k__DCT_CONST_ROUNDING);
-
-  s[0] = _mm_srli_epi64(s[0], DCT_CONST_BITS);
-  s[1] = _mm_srli_epi64(s[1], DCT_CONST_BITS);
-  s[2] = _mm_srli_epi64(s[2], DCT_CONST_BITS);
-  s[3] = _mm_srli_epi64(s[3], DCT_CONST_BITS);
-  s[4] = _mm_srli_epi64(s[4], DCT_CONST_BITS);
-  s[5] = _mm_srli_epi64(s[5], DCT_CONST_BITS);
-  s[6] = _mm_srli_epi64(s[6], DCT_CONST_BITS);
-  s[7] = _mm_srli_epi64(s[7], DCT_CONST_BITS);
-
-  s[0] = _mm_shuffle_epi32(s[0], 0x88);
-  s[1] = _mm_shuffle_epi32(s[1], 0x88);
-  s[2] = _mm_shuffle_epi32(s[2], 0x88);
-  s[3] = _mm_shuffle_epi32(s[3], 0x88);
-  s[4] = _mm_shuffle_epi32(s[4], 0x88);
-  s[5] = _mm_shuffle_epi32(s[5], 0x88);
-  s[6] = _mm_shuffle_epi32(s[6], 0x88);
-  s[7] = _mm_shuffle_epi32(s[7], 0x88);
-
-  v0 = _mm_unpacklo_epi32(s[0], s[4]);
-  v1 = _mm_unpacklo_epi32(s[2], s[6]);
-  v2 = _mm_unpacklo_epi32(s[1], s[5]);
-  v3 = _mm_unpacklo_epi32(s[3], s[7]);
-
-  in[0] = _mm_unpacklo_epi64(v0, v1);
-  in[1] = _mm_unpackhi_epi64(v0, v1);
-  in[2] = _mm_unpacklo_epi64(v2, v3);
-  in[3] = _mm_unpackhi_epi64(v2, v3);
+  in[0] = _mm_unpacklo_epi64(v0, v2);
+  in[1] = _mm_unpackhi_epi64(v0, v2);
+  in[2] = _mm_unpacklo_epi64(v1, v3);
+  in[3] = _mm_unpackhi_epi64(v1, v3);
 }
 
 static INLINE void write_buffer_4x4(tran_low_t *output, __m128i *res) {
-  const __m128i kOne = _mm_set1_epi32(1);
-  res[0] = _mm_add_epi32(res[0], kOne);
-  res[1] = _mm_add_epi32(res[1], kOne);
-  res[2] = _mm_add_epi32(res[2], kOne);
-  res[3] = _mm_add_epi32(res[3], kOne);
-  res[0] = _mm_srai_epi32(res[0], 2);
-  res[1] = _mm_srai_epi32(res[1], 2);
-  res[2] = _mm_srai_epi32(res[2], 2);
-  res[3] = _mm_srai_epi32(res[3], 2);
   _mm_store_si128((__m128i *)(output + 0 * 4), res[0]);
   _mm_store_si128((__m128i *)(output + 1 * 4), res[1]);
   _mm_store_si128((__m128i *)(output + 2 * 4), res[2]);
@@ -169,12 +121,17 @@
 void vp10_highbd_fht4x4_sse4_1(const int16_t *input, tran_low_t *output,
                                int stride, int tx_type) {
   __m128i in[4];
+  const TXFM_2D_CFG *cfg;
+  int bit;
 
   switch (tx_type) {
     case DCT_DCT:
-      load_buffer_4x4(input, in, stride, 0, 0);
-      fdct4x4_sse4_1(in);
-      fdct4x4_sse4_1(in);
+      cfg = &fwd_txfm_2d_cfg_dct_dct_4;
+      load_buffer_4x4(input, in, stride, 0, 0, cfg->shift[0]);
+      bit = cfg->cos_bit_col[2];
+      fdct4x4_sse4_1(in, bit);
+      bit = cfg->cos_bit_row[2];
+      fdct4x4_sse4_1(in, bit);
       write_buffer_4x4(output, in);
       break;
     case ADST_DCT:
diff --git a/vp10/vp10_common.mk b/vp10/vp10_common.mk
index 40699a3..89b0edb 100644
--- a/vp10/vp10_common.mk
+++ b/vp10/vp10_common.mk
@@ -68,10 +68,8 @@
 VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm1d.c
 VP10_COMMON_SRCS-yes += common/vp10_inv_txfm1d.h
 VP10_COMMON_SRCS-yes += common/vp10_inv_txfm1d.c
-VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d.h
 VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d.c
 VP10_COMMON_SRCS-yes += common/vp10_fwd_txfm2d_cfg.h
-VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d.h
 VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d.c
 VP10_COMMON_SRCS-yes += common/vp10_inv_txfm2d_cfg.h
 VP10_COMMON_SRCS-yes += common/vp10_convolve.c
diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c
index 5ae44e8..cff99c0 100644
--- a/vp8/encoder/denoising.c
+++ b/vp8/encoder/denoising.c
@@ -497,7 +497,8 @@
                              loop_filter_info_n *lfi_n,
                              int mb_row,
                              int mb_col,
-                             int block_index)
+                             int block_index,
+                             int consec_zero_last)
 
 {
     int mv_row;
@@ -571,58 +572,69 @@
             best_sse = zero_mv_sse;
         }
 
-        saved_pre = filter_xd->pre;
-        saved_dst = filter_xd->dst;
+        mv_row = x->best_sse_mv.as_mv.row;
+        mv_col = x->best_sse_mv.as_mv.col;
+        motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
+        motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
+            NOISE_MOTION_THRESHOLD;
 
-        /* Compensate the running average. */
-        filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
-        filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
-        filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
-        /* Write the compensated running average to the destination buffer. */
-        filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
-        filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
-        filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
+        if (motion_magnitude2 <
+          denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
+          x->increase_denoising = 1;
 
-        if (!x->skip)
-        {
-            vp8_build_inter_predictors_mb(filter_xd);
+        sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
+        if (x->increase_denoising)
+          sse_thresh =
+              denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
+
+        if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
+          decision = COPY_BLOCK;
+
+        // If block is considered skin, don't denoise if the block
+        // (1) is selected as non-zero motion for current frame, or
+        // (2) has not been selected as ZERO_LAST mode at least x past frames
+        // in a row.
+        // TODO(marpan): Parameter "x" should be varied with framerate.
+        // In particualar, should be reduced for layers (base layer/LAST).
+        if (x->is_skin && (consec_zero_last < 2 || motion_magnitude2 > 0))
+          decision = COPY_BLOCK;
+
+        if (decision == FILTER_BLOCK) {
+          saved_pre = filter_xd->pre;
+          saved_dst = filter_xd->dst;
+
+          /* Compensate the running average. */
+          filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset;
+          filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset;
+          filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset;
+          /* Write the compensated running average to the destination buffer. */
+          filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset;
+          filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset;
+          filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset;
+
+          if (!x->skip)
+          {
+              vp8_build_inter_predictors_mb(filter_xd);
+          }
+          else
+          {
+              vp8_build_inter16x16_predictors_mb(filter_xd,
+                                                 filter_xd->dst.y_buffer,
+                                                 filter_xd->dst.u_buffer,
+                                                 filter_xd->dst.v_buffer,
+                                                 filter_xd->dst.y_stride,
+                                                 filter_xd->dst.uv_stride);
+          }
+          filter_xd->pre = saved_pre;
+          filter_xd->dst = saved_dst;
+          *mbmi = saved_mbmi;
         }
-        else
-        {
-            vp8_build_inter16x16_predictors_mb(filter_xd,
-                                               filter_xd->dst.y_buffer,
-                                               filter_xd->dst.u_buffer,
-                                               filter_xd->dst.v_buffer,
-                                               filter_xd->dst.y_stride,
-                                               filter_xd->dst.uv_stride);
-        }
-        filter_xd->pre = saved_pre;
-        filter_xd->dst = saved_dst;
-        *mbmi = saved_mbmi;
-
-    }
-
-    mv_row = x->best_sse_mv.as_mv.row;
-    mv_col = x->best_sse_mv.as_mv.col;
-    motion_magnitude2 = mv_row * mv_row + mv_col * mv_col;
-    motion_threshold = denoiser->denoise_pars.scale_motion_thresh *
-        NOISE_MOTION_THRESHOLD;
-
-    // If block is considered to be skin area, lower the motion threshold.
-    // In current version set threshold = 0, so only denoise zero mv on skin.
-    if (x->is_skin)
-        motion_threshold = 0;
-
-    if (motion_magnitude2 <
-        denoiser->denoise_pars.scale_increase_filter * NOISE_MOTION_THRESHOLD)
-      x->increase_denoising = 1;
-
-    sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD;
-    if (x->increase_denoising)
-      sse_thresh = denoiser->denoise_pars.scale_sse_thresh * SSE_THRESHOLD_HIGH;
-
-    if (best_sse > sse_thresh || motion_magnitude2 > motion_threshold)
+    } else {
+      // zero_frame should always be 1 for real-time mode, as the
+      // ZEROMV mode is always checked, so we should never go into this branch.
+      // If case ZEROMV is not checked, then we will force no denoise (COPY).
       decision = COPY_BLOCK;
+    }
 
     if (decision == FILTER_BLOCK)
     {
diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h
index 148ccda..34c561d 100644
--- a/vp8/encoder/denoising.h
+++ b/vp8/encoder/denoising.h
@@ -108,7 +108,8 @@
                              loop_filter_info_n *lfi_n,
                              int mb_row,
                              int mb_col,
-                             int block_index);
+                             int block_index,
+                             int consec_zero_last);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c
index 51fbe54..0708d65 100644
--- a/vp8/encoder/pickinter.c
+++ b/vp8/encoder/pickinter.c
@@ -36,7 +36,7 @@
 extern unsigned int cnt_pm;
 #endif
 
-#define MODEL_MODE 0
+#define MODEL_MODE 1
 
 extern const int vp8_ref_frame_order[MAX_MODES];
 extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES];
@@ -1477,7 +1477,8 @@
         vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
                                 recon_yoffset, recon_uvoffset,
                                 &cpi->common.lf_info, mb_row, mb_col,
-                                block_index);
+                                block_index,
+                                cpi->consec_zero_last_mvbias[block_index]);
 
         // Reevaluate ZEROMV after denoising: for large noise content
         // (i.e., cpi->mse_source_denoised is above threshold), do this for all
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index ab0ad15..9063cea 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -2530,7 +2530,7 @@
         vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse,
                                 recon_yoffset, recon_uvoffset,
                                 &cpi->common.lf_info, mb_row, mb_col,
-                                block_index);
+                                block_index, 0);
 
         /* Reevaluate ZEROMV after denoising. */
         if (best_mode.mbmode.ref_frame == INTRA_FRAME &&
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c
index 9b58f81..9c78de1 100644
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -9,6 +9,7 @@
  */
 
 
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include "./vp8_rtcd.h"
@@ -154,6 +155,8 @@
 {
     vpx_codec_err_t res = VPX_CODEC_OK;
 
+    assert(data != NULL);
+
     if(data + data_sz <= data)
     {
         res = VPX_CODEC_INVALID_PARAM;
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index ae2f66a..3d26fb2 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -158,8 +158,8 @@
   MODE_INFO *left_mi;
   MODE_INFO *above_mi;
 
-  int up_available;
-  int left_available;
+  unsigned int max_blocks_wide;
+  unsigned int max_blocks_high;
 
   const vpx_prob (*partition_probs)[PARTITION_TYPES - 1];
 
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index fd674cb..3fd935e 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -404,20 +404,8 @@
   xd->mb_to_right_edge  = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
 
   // Are edges available for intra prediction?
-  xd->up_available    = (mi_row != 0);
-  xd->left_available  = (mi_col > tile->mi_col_start);
-  // TODO(slavarnway): eliminate up/left available ???
-  if (xd->up_available) {
-    xd->above_mi = xd->mi[-xd->mi_stride];
-  } else {
-    xd->above_mi = NULL;
-  }
-
-  if (xd->left_available) {
-    xd->left_mi = xd->mi[-1];
-  } else {
-    xd->left_mi = NULL;
-  }
+  xd->above_mi = (mi_row != 0) ? xd->mi[-xd->mi_stride] : NULL;
+  xd->left_mi  = (mi_col > tile->mi_col_start) ? xd->mi[-1] : NULL;
 }
 
 static INLINE void update_partition_context(MACROBLOCKD *xd,
diff --git a/vp9/common/vp9_pred_common.c b/vp9/common/vp9_pred_common.c
index 0a36dba..b5751fc 100644
--- a/vp9/common/vp9_pred_common.c
+++ b/vp9/common/vp9_pred_common.c
@@ -20,10 +20,10 @@
   // left of the entries corresponding to real macroblocks.
   // The prediction flags in these dummy entries are initialized to 0.
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int left_type = xd->left_available && is_inter_block(left_mi) ?
+  const int left_type = left_mi && is_inter_block(left_mi) ?
                             left_mi->interp_filter : SWITCHABLE_FILTERS;
   const MODE_INFO *const above_mi = xd->above_mi;
-  const int above_type = xd->up_available && is_inter_block(above_mi) ?
+  const int above_type = above_mi && is_inter_block(above_mi) ?
                              above_mi->interp_filter : SWITCHABLE_FILTERS;
 
   if (left_type == above_type)
@@ -36,38 +36,13 @@
     return SWITCHABLE_FILTERS;
 }
 
-// The mode info data structure has a one element border above and to the
-// left of the entries corresponding to real macroblocks.
-// The prediction flags in these dummy entries are initialized to 0.
-// 0 - inter/inter, inter/--, --/inter, --/--
-// 1 - intra/inter, inter/intra
-// 2 - intra/--, --/intra
-// 3 - intra/intra
-int vp9_get_intra_inter_context(const MACROBLOCKD *xd) {
-  const MODE_INFO *const above_mi = xd->above_mi;
-  const MODE_INFO *const left_mi = xd->left_mi;
-  const int has_above = xd->up_available;
-  const int has_left = xd->left_available;
-
-  if (has_above && has_left) {  // both edges available
-    const int above_intra = !is_inter_block(above_mi);
-    const int left_intra = !is_inter_block(left_mi);
-    return left_intra && above_intra ? 3
-                                     : left_intra || above_intra;
-  } else if (has_above || has_left) {  // one edge available
-    return 2 * !is_inter_block(has_above ? above_mi : left_mi);
-  } else {
-    return 0;
-  }
-}
-
 int vp9_get_reference_mode_context(const VP9_COMMON *cm,
                                    const MACROBLOCKD *xd) {
   int ctx;
   const MODE_INFO *const above_mi = xd->above_mi;
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int has_above = xd->up_available;
-  const int has_left = xd->left_available;
+  const int has_above = !!above_mi;
+  const int has_left = !!left_mi;
   // Note:
   // The mode info data structure has a one element border above and to the
   // left of the entries corresponding to real macroblocks.
@@ -109,8 +84,8 @@
   int pred_context;
   const MODE_INFO *const above_mi = xd->above_mi;
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int above_in_image = xd->up_available;
-  const int left_in_image = xd->left_available;
+  const int above_in_image = !!above_mi;
+  const int left_in_image = !!left_mi;
 
   // Note:
   // The mode info data structure has a one element border above and to the
@@ -190,9 +165,8 @@
   int pred_context;
   const MODE_INFO *const above_mi = xd->above_mi;
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int has_above = xd->up_available;
-  const int has_left = xd->left_available;
-
+  const int has_above = !!above_mi;
+  const int has_left = !!left_mi;
   // Note:
   // The mode info data structure has a one element border above and to the
   // left of the entries corresponding to real macroblocks.
@@ -257,8 +231,8 @@
   int pred_context;
   const MODE_INFO *const above_mi = xd->above_mi;
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int has_above = xd->up_available;
-  const int has_left = xd->left_available;
+  const int has_above = !!above_mi;
+  const int has_left = !!left_mi;
 
   // Note:
   // The mode info data structure has a one element border above and to the
diff --git a/vp9/common/vp9_pred_common.h b/vp9/common/vp9_pred_common.h
index 254cb8b..f3c676e 100644
--- a/vp9/common/vp9_pred_common.h
+++ b/vp9/common/vp9_pred_common.h
@@ -68,11 +68,32 @@
 
 int vp9_get_pred_context_switchable_interp(const MACROBLOCKD *xd);
 
-int vp9_get_intra_inter_context(const MACROBLOCKD *xd);
+// The mode info data structure has a one element border above and to the
+// left of the entries corresponding to real macroblocks.
+// The prediction flags in these dummy entries are initialized to 0.
+// 0 - inter/inter, inter/--, --/inter, --/--
+// 1 - intra/inter, inter/intra
+// 2 - intra/--, --/intra
+// 3 - intra/intra
+static INLINE int get_intra_inter_context(const MACROBLOCKD *xd) {
+  const MODE_INFO *const above_mi = xd->above_mi;
+  const MODE_INFO *const left_mi = xd->left_mi;
+  const int has_above = !!above_mi;
+  const int has_left = !!left_mi;
+
+  if (has_above && has_left) {  // both edges available
+    const int above_intra = !is_inter_block(above_mi);
+    const int left_intra = !is_inter_block(left_mi);
+    return left_intra && above_intra ? 3 : left_intra || above_intra;
+  } else if (has_above || has_left) {  // one edge available
+    return 2 * !is_inter_block(has_above ? above_mi : left_mi);
+  }
+  return 0;
+}
 
 static INLINE vpx_prob vp9_get_intra_inter_prob(const VP9_COMMON *cm,
                                                 const MACROBLOCKD *xd) {
-  return cm->fc->intra_inter_prob[vp9_get_intra_inter_context(xd)];
+  return cm->fc->intra_inter_prob[get_intra_inter_context(xd)];
 }
 
 int vp9_get_reference_mode_context(const VP9_COMMON *cm, const MACROBLOCKD *xd);
@@ -113,8 +134,8 @@
   const int max_tx_size = max_txsize_lookup[xd->mi[0]->sb_type];
   const MODE_INFO *const above_mi = xd->above_mi;
   const MODE_INFO *const left_mi = xd->left_mi;
-  const int has_above = xd->up_available;
-  const int has_left = xd->left_available;
+  const int has_above = !!above_mi;
+  const int has_left = !!left_mi;
   int above_ctx = (has_above && !above_mi->skip) ? (int)above_mi->tx_size
                                                  : max_tx_size;
   int left_ctx = (has_left && !left_mi->skip) ? (int)left_mi->tx_size
diff --git a/vp9/common/vp9_reconintra.c b/vp9/common/vp9_reconintra.c
index 13a95ae..c4d91c8 100644
--- a/vp9/common/vp9_reconintra.c
+++ b/vp9/common/vp9_reconintra.c
@@ -425,8 +425,8 @@
                              int aoff, int loff, int plane) {
   const int bw = (1 << bwl_in);
   const int txw = (1 << tx_size);
-  const int have_top = loff || xd->up_available;
-  const int have_left = aoff || xd->left_available;
+  const int have_top = loff || (xd->above_mi != NULL);
+  const int have_left = aoff || (xd->left_mi != NULL);
   const int have_right = (aoff + txw) < bw;
   const int x = aoff * 4;
   const int y = loff * 4;
diff --git a/vp9/common/vp9_rtcd_defs.pl b/vp9/common/vp9_rtcd_defs.pl
index d6a0ce9..1cf636c 100644
--- a/vp9/common/vp9_rtcd_defs.pl
+++ b/vp9/common/vp9_rtcd_defs.pl
@@ -276,7 +276,7 @@
 $vp9_full_search_sad_sse4_1=vp9_full_search_sadx8;
 
 add_proto qw/int vp9_diamond_search_sad/, "const struct macroblock *x, const struct search_site_config *cfg,  struct mv *ref_mv, struct mv *best_mv, int search_param, int sad_per_bit, int *num00, const struct vp9_variance_vtable *fn_ptr, const struct mv *center_mv";
-specialize qw/vp9_diamond_search_sad avx/;
+specialize qw/vp9_diamond_search_sad/;
 
 add_proto qw/void vp9_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count";
 specialize qw/vp9_temporal_filter_apply sse2 msa/;
diff --git a/vp9/common/vp9_scan.c b/vp9/common/vp9_scan.c
index d6fb8b2..8b8b09f 100644
--- a/vp9/common/vp9_scan.c
+++ b/vp9/common/vp9_scan.c
@@ -229,10 +229,8 @@
   990, 959, 1022, 991, 1023,
 };
 
-// Neighborhood 5-tuples for various scans and blocksizes,
-// in {top, left, topleft, topright, bottomleft} order
-// for each position in raster scan order.
-// -1 indicates the neighbor does not exist.
+// Neighborhood 2-tuples for various scans and blocksizes,
+// in {top, left} order for each position in corresponding scan order.
 DECLARE_ALIGNED(16, static const int16_t,
                 default_scan_4x4_neighbors[17 * MAX_NEIGHBORS]) = {
   0, 0, 0, 0, 0, 0, 1, 4, 4, 4, 1, 1, 8, 8, 5, 8, 2, 2, 2, 5, 9, 12, 6, 9,
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 32c7219..2c2c0ba 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -883,6 +883,9 @@
       const int max_blocks_high = num_4x4_h + (xd->mb_to_bottom_edge >= 0 ?
           0 : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
 
+      xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+      xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
       for (row = 0; row < max_blocks_high; row += step)
         for (col = 0; col < max_blocks_wide; col += step)
           predict_and_reconstruct_intra_block(xd, r, mi, plane,
@@ -911,6 +914,9 @@
         const int max_blocks_high = num_4x4_h + (xd->mb_to_bottom_edge >= 0 ?
             0 : xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
 
+        xd->max_blocks_wide = xd->mb_to_right_edge >= 0 ? 0 : max_blocks_wide;
+        xd->max_blocks_high = xd->mb_to_bottom_edge >= 0 ? 0 : max_blocks_high;
+
         for (row = 0; row < max_blocks_high; row += step)
           for (col = 0; col < max_blocks_wide; col += step)
             eobtotal += reconstruct_inter_block(xd, r, mi, plane, row, col,
@@ -1462,7 +1468,7 @@
   TileBuffer tile_buffers[4][1 << 6];
   int tile_row, tile_col;
   int mi_row, mi_col;
-  TileData *tile_data = NULL;
+  TileWorkerData *tile_data = NULL;
 
   if (cm->lf.filter_level && !cm->skip_loop_filter &&
       pbi->lf_worker.data1 == NULL) {
@@ -1498,28 +1504,17 @@
 
   get_tile_buffers(pbi, data, data_end, tile_cols, tile_rows, tile_buffers);
 
-  if (pbi->tile_data == NULL ||
-      (tile_cols * tile_rows) != pbi->total_tiles) {
-    vpx_free(pbi->tile_data);
-    CHECK_MEM_ERROR(
-        cm,
-        pbi->tile_data,
-        vpx_memalign(32, tile_cols * tile_rows * (sizeof(*pbi->tile_data))));
-    pbi->total_tiles = tile_rows * tile_cols;
-  }
-
   // Load all tile information into tile_data.
   for (tile_row = 0; tile_row < tile_rows; ++tile_row) {
     for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
       const TileBuffer *const buf = &tile_buffers[tile_row][tile_col];
-      tile_data = pbi->tile_data + tile_cols * tile_row + tile_col;
-      tile_data->cm = cm;
+      tile_data = pbi->tile_worker_data + tile_cols * tile_row + tile_col;
       tile_data->xd = pbi->mb;
       tile_data->xd.corrupted = 0;
-      tile_data->xd.counts = cm->frame_parallel_decoding_mode ?
-                             NULL : &cm->counts;
+      tile_data->xd.counts =
+          cm->frame_parallel_decoding_mode ? NULL : &cm->counts;
       vp9_zero(tile_data->dqcoeff);
-      vp9_tile_init(&tile_data->xd.tile, tile_data->cm, tile_row, tile_col);
+      vp9_tile_init(&tile_data->xd.tile, cm, tile_row, tile_col);
       setup_token_decoder(buf->data, data_end, buf->size, &cm->error,
                           &tile_data->bit_reader, pbi->decrypt_cb,
                           pbi->decrypt_state);
@@ -1535,8 +1530,8 @@
       for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
         const int col = pbi->inv_tile_order ?
                         tile_cols - tile_col - 1 : tile_col;
-        tile_data = pbi->tile_data + tile_cols * tile_row + col;
-        vp9_tile_set_col(&tile, tile_data->cm, col);
+        tile_data = pbi->tile_worker_data + tile_cols * tile_row + col;
+        vp9_tile_set_col(&tile, cm, col);
         vp9_zero(tile_data->xd.left_context);
         vp9_zero(tile_data->xd.left_seg_context);
         for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end;
@@ -1588,7 +1583,7 @@
   }
 
   // Get last tile data.
-  tile_data = pbi->tile_data + tile_cols * tile_rows - 1;
+  tile_data = pbi->tile_worker_data + tile_cols * tile_rows - 1;
 
   if (pbi->frame_parallel_decode)
     vp9_frameworker_broadcast(pbi->cur_buf, INT_MAX);
@@ -1673,12 +1668,6 @@
     const int num_threads = pbi->max_threads;
     CHECK_MEM_ERROR(cm, pbi->tile_workers,
                     vpx_malloc(num_threads * sizeof(*pbi->tile_workers)));
-    // Ensure tile data offsets will be properly aligned. This may fail on
-    // platforms without DECLARE_ALIGNED().
-    assert((sizeof(*pbi->tile_worker_data) % 16) == 0);
-    CHECK_MEM_ERROR(cm, pbi->tile_worker_data,
-                    vpx_memalign(32, num_threads *
-                                 sizeof(*pbi->tile_worker_data)));
     for (n = 0; n < num_threads; ++n) {
       VPxWorker *const worker = &pbi->tile_workers[n];
       ++pbi->num_tile_workers;
@@ -1694,7 +1683,8 @@
   // Reset tile decoding hook
   for (n = 0; n < num_workers; ++n) {
     VPxWorker *const worker = &pbi->tile_workers[n];
-    TileWorkerData *const tile_data = &pbi->tile_worker_data[n];
+    TileWorkerData *const tile_data =
+        &pbi->tile_worker_data[n + pbi->total_tiles];
     winterface->sync(worker);
     tile_data->xd = pbi->mb;
     tile_data->xd.counts =
@@ -2223,6 +2213,19 @@
     vp9_frameworker_unlock_stats(worker);
   }
 
+  if (pbi->tile_worker_data == NULL ||
+      (tile_cols * tile_rows) != pbi->total_tiles) {
+    const int num_tile_workers = tile_cols * tile_rows +
+        ((pbi->max_threads > 1) ? pbi->max_threads : 0);
+    const size_t twd_size = num_tile_workers * sizeof(*pbi->tile_worker_data);
+    // Ensure tile data offsets will be properly aligned. This may fail on
+    // platforms without DECLARE_ALIGNED().
+    assert((sizeof(*pbi->tile_worker_data) % 16) == 0);
+    vpx_free(pbi->tile_worker_data);
+    CHECK_MEM_ERROR(cm, pbi->tile_worker_data, vpx_memalign(32, twd_size));
+    pbi->total_tiles = tile_rows * tile_cols;
+  }
+
   if (pbi->max_threads > 1 && tile_rows == 1 && tile_cols > 1) {
     // Multi-threaded tile decoder
     *p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end);
diff --git a/vp9/decoder/vp9_decodemv.c b/vp9/decoder/vp9_decodemv.c
index 596427c..8831de9 100644
--- a/vp9/decoder/vp9_decodemv.c
+++ b/vp9/decoder/vp9_decodemv.c
@@ -353,11 +353,36 @@
   }
 }
 
+// TODO(slavarnway): Move this decoder version of
+// vp9_get_pred_context_switchable_interp() to vp9_pred_common.h and update the
+// encoder.
+//
+// Returns a context number for the given MB prediction signal
+static int dec_get_pred_context_switchable_interp(const MACROBLOCKD *xd) {
+  // Note:
+  // The mode info data structure has a one element border above and to the
+  // left of the entries corresponding to real macroblocks.
+  // The prediction flags in these dummy entries are initialized to 0.
+  const MODE_INFO *const left_mi = xd->left_mi;
+  const int left_type = left_mi ? left_mi->interp_filter : SWITCHABLE_FILTERS;
+  const MODE_INFO *const above_mi = xd->above_mi;
+  const int above_type = above_mi ? above_mi->interp_filter
+                             : SWITCHABLE_FILTERS;
+
+  if (left_type == above_type)
+    return left_type;
+  else if (left_type == SWITCHABLE_FILTERS && above_type != SWITCHABLE_FILTERS)
+    return above_type;
+  else if (left_type != SWITCHABLE_FILTERS && above_type == SWITCHABLE_FILTERS)
+    return left_type;
+  else
+    return SWITCHABLE_FILTERS;
+}
 
 static INLINE INTERP_FILTER read_switchable_interp_filter(
     VP9_COMMON *const cm, MACROBLOCKD *const xd,
     vpx_reader *r) {
-  const int ctx = vp9_get_pred_context_switchable_interp(xd);
+  const int ctx = dec_get_pred_context_switchable_interp(xd);
   const INTERP_FILTER type =
       (INTERP_FILTER)vpx_read_tree(r, vp9_switchable_interp_tree,
                                    cm->fc->switchable_interp_prob[ctx]);
@@ -373,9 +398,6 @@
   const BLOCK_SIZE bsize = mi->sb_type;
   int i;
 
-  mi->ref_frame[0] = INTRA_FRAME;
-  mi->ref_frame[1] = NONE;
-
   switch (bsize) {
     case BLOCK_4X4:
       for (i = 0; i < 4; ++i)
@@ -399,6 +421,13 @@
   }
 
   mi->uv_mode = read_intra_mode_uv(cm, xd, r, mi->mode);
+
+  // Initialize interp_filter here so we do not have to check for inter block
+  // modes in dec_get_pred_context_switchable_interp()
+  mi->interp_filter = SWITCHABLE_FILTERS;
+
+  mi->ref_frame[0] = INTRA_FRAME;
+  mi->ref_frame[1] = NONE;
 }
 
 static INLINE int is_mv_valid(const MV *mv) {
@@ -454,7 +483,7 @@
   if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
     return get_segdata(&cm->seg, segment_id, SEG_LVL_REF_FRAME) != INTRA_FRAME;
   } else {
-    const int ctx = vp9_get_intra_inter_context(xd);
+    const int ctx = get_intra_inter_context(xd);
     const int is_inter = vpx_read(r, cm->fc->intra_inter_prob[ctx]);
     FRAME_COUNTS *counts = xd->counts;
     if (counts)
diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c
index 3e06c8e..dde609b 100644
--- a/vp9/decoder/vp9_decoder.c
+++ b/vp9/decoder/vp9_decoder.c
@@ -131,11 +131,12 @@
 
   vpx_get_worker_interface()->end(&pbi->lf_worker);
   vpx_free(pbi->lf_worker.data1);
-  vpx_free(pbi->tile_data);
+
   for (i = 0; i < pbi->num_tile_workers; ++i) {
     VPxWorker *const worker = &pbi->tile_workers[i];
     vpx_get_worker_interface()->end(worker);
   }
+
   vpx_free(pbi->tile_worker_data);
   vpx_free(pbi->tile_workers);
 
@@ -239,7 +240,6 @@
   RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
 
   lock_buffer_pool(pool);
-
   for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
     const int old_idx = cm->ref_frame_map[ref_index];
     // Current thread releases the holding of reference frame.
@@ -308,8 +308,11 @@
                         &frame_bufs[cm->new_fb_idx].raw_frame_buffer);
   // Find a free frame buffer. Return error if can not find any.
   cm->new_fb_idx = get_free_fb(cm);
-  if (cm->new_fb_idx == INVALID_IDX)
-    return VPX_CODEC_MEM_ERROR;
+  if (cm->new_fb_idx == INVALID_IDX) {
+    vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
+                       "Unable to find free frame buffer");
+    return cm->error.error_code;
+  }
 
   // Assign a MV array to the frame buffer.
   cm->cur_frame = &pool->frame_bufs[cm->new_fb_idx];
diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h
index afa4009..7111a36 100644
--- a/vp9/decoder/vp9_decoder.h
+++ b/vp9/decoder/vp9_decoder.h
@@ -27,15 +27,6 @@
 extern "C" {
 #endif
 
-// TODO(hkuang): combine this with TileWorkerData.
-typedef struct TileData {
-  VP9_COMMON *cm;
-  vpx_reader bit_reader;
-  DECLARE_ALIGNED(16, MACROBLOCKD, xd);
-  /* dqcoeff are shared by all the planes. So planes must be decoded serially */
-  DECLARE_ALIGNED(16, tran_low_t, dqcoeff[32 * 32]);
-} TileData;
-
 typedef struct TileBuffer {
   const uint8_t *data;
   size_t size;
@@ -74,8 +65,6 @@
   TileWorkerData *tile_worker_data;
   TileBuffer tile_buffers[64];
   int num_tile_workers;
-
-  TileData *tile_data;
   int total_tiles;
 
   VP9LfSync lf_row_sync;
diff --git a/vp9/decoder/vp9_detokenize.c b/vp9/decoder/vp9_detokenize.c
index dcc75b9..47dc107 100644
--- a/vp9/decoder/vp9_detokenize.c
+++ b/vp9/decoder/vp9_detokenize.c
@@ -152,65 +152,73 @@
   return c;
 }
 
-// TODO(slavarnway): Decode version of vp9_set_context.  Modify vp9_set_context
-// after testing is complete, then delete this version.
-static
-void dec_set_contexts(const MACROBLOCKD *xd, struct macroblockd_plane *pd,
-                      TX_SIZE tx_size, int has_eob,
-                      int aoff, int loff) {
-  ENTROPY_CONTEXT *const a = pd->above_context + aoff;
-  ENTROPY_CONTEXT *const l = pd->left_context + loff;
-  const int tx_size_in_blocks = 1 << tx_size;
-
-  // above
-  if (has_eob && xd->mb_to_right_edge < 0) {
-    int i;
-    const int blocks_wide = pd->n4_w +
-                            (xd->mb_to_right_edge >> (5 + pd->subsampling_x));
-    int above_contexts = tx_size_in_blocks;
-    if (above_contexts + aoff > blocks_wide)
-      above_contexts = blocks_wide - aoff;
-
-    for (i = 0; i < above_contexts; ++i)
-      a[i] = has_eob;
-    for (i = above_contexts; i < tx_size_in_blocks; ++i)
-      a[i] = 0;
-  } else {
-    memset(a, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
+static void get_ctx_shift(MACROBLOCKD *xd, int *ctx_shift_a, int *ctx_shift_l,
+                          int x, int y, unsigned int tx_size_in_blocks) {
+  if (xd->max_blocks_wide) {
+    if (tx_size_in_blocks + x > xd->max_blocks_wide)
+      *ctx_shift_a = (tx_size_in_blocks - (xd->max_blocks_wide - x)) * 8;
   }
-
-  // left
-  if (has_eob && xd->mb_to_bottom_edge < 0) {
-    int i;
-    const int blocks_high = pd->n4_h +
-                            (xd->mb_to_bottom_edge >> (5 + pd->subsampling_y));
-    int left_contexts = tx_size_in_blocks;
-    if (left_contexts + loff > blocks_high)
-      left_contexts = blocks_high - loff;
-
-    for (i = 0; i < left_contexts; ++i)
-      l[i] = has_eob;
-    for (i = left_contexts; i < tx_size_in_blocks; ++i)
-      l[i] = 0;
-  } else {
-    memset(l, has_eob, sizeof(ENTROPY_CONTEXT) * tx_size_in_blocks);
+  if (xd->max_blocks_high) {
+    if (tx_size_in_blocks + y > xd->max_blocks_high)
+      *ctx_shift_l = (tx_size_in_blocks - (xd->max_blocks_high - y)) * 8;
   }
 }
 
-int vp9_decode_block_tokens(MACROBLOCKD *xd,
-                            int plane, const scan_order *sc,
-                            int x, int y,
-                            TX_SIZE tx_size, vpx_reader *r,
+int vp9_decode_block_tokens(MACROBLOCKD *xd, int plane, const scan_order *sc,
+                            int x, int y, TX_SIZE tx_size, vpx_reader *r,
                             int seg_id) {
   struct macroblockd_plane *const pd = &xd->plane[plane];
   const int16_t *const dequant = pd->seg_dequant[seg_id];
-  const int ctx = get_entropy_context(tx_size, pd->above_context + x,
-                                               pd->left_context + y);
-  const int eob = decode_coefs(xd, get_plane_type(plane),
-                               pd->dqcoeff, tx_size,
-                               dequant, ctx, sc->scan, sc->neighbors, r);
-  dec_set_contexts(xd, pd, tx_size, eob > 0, x, y);
+  int eob;
+  ENTROPY_CONTEXT *a = pd->above_context + x;
+  ENTROPY_CONTEXT *l = pd->left_context + y;
+  int ctx;
+  int ctx_shift_a = 0;
+  int ctx_shift_l = 0;
+
+  switch (tx_size) {
+    case TX_4X4:
+      ctx  = a[0] != 0;
+      ctx += l[0] != 0;
+      eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+                         dequant, ctx, sc->scan, sc->neighbors, r);
+      a[0] = l[0] = (eob > 0);
+      break;
+    case TX_8X8:
+      get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_8X8);
+      ctx  = !!*(const uint16_t *)a;
+      ctx += !!*(const uint16_t *)l;
+      eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+                         dequant, ctx, sc->scan, sc->neighbors, r);
+      *(uint16_t *)a = ((eob > 0) * 0x0101) >> ctx_shift_a;
+      *(uint16_t *)l = ((eob > 0) * 0x0101) >> ctx_shift_l;
+      break;
+    case TX_16X16:
+      get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_16X16);
+      ctx  = !!*(const uint32_t *)a;
+      ctx += !!*(const uint32_t *)l;
+      eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+                         dequant, ctx, sc->scan, sc->neighbors, r);
+      *(uint32_t *)a = ((eob > 0) * 0x01010101) >> ctx_shift_a;
+      *(uint32_t *)l = ((eob > 0) * 0x01010101) >> ctx_shift_l;
+      break;
+    case TX_32X32:
+      get_ctx_shift(xd, &ctx_shift_a, &ctx_shift_l, x, y, 1 << TX_32X32);
+      // NOTE: casting to uint64_t here is safe because the default memory
+      // alignment is at least 8 bytes and the TX_32X32 is aligned on 8 byte
+      // boundaries.
+      ctx  = !!*(const uint64_t *)a;
+      ctx += !!*(const uint64_t *)l;
+      eob = decode_coefs(xd, get_plane_type(plane), pd->dqcoeff, tx_size,
+                         dequant, ctx, sc->scan, sc->neighbors, r);
+      *(uint64_t *)a = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_a;
+      *(uint64_t *)l = ((eob > 0) * 0x0101010101010101ULL) >> ctx_shift_l;
+      break;
+    default:
+      assert(0 && "Invalid transform size.");
+      eob = 0;
+      break;
+  }
+
   return eob;
 }
-
-
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index 9f8004b..5600ed4 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -210,7 +210,7 @@
     if (cm->reference_mode == REFERENCE_MODE_SELECT) {
       vpx_write(w, is_compound, vp9_get_reference_mode_prob(cm, xd));
     } else {
-      assert((!is_compound) == (cm->reference_mode == SINGLE_REFERENCE));
+      assert(!is_compound == (cm->reference_mode == SINGLE_REFERENCE));
     }
 
     if (is_compound) {
diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c
index 9bc9f26..dbca633 100644
--- a/vp9/encoder/vp9_denoiser.c
+++ b/vp9/encoder/vp9_denoiser.c
@@ -183,7 +183,7 @@
 
 static uint8_t *block_start(uint8_t *framebuf, int stride,
                             int mi_row, int mi_col) {
-  return framebuf + (stride * mi_row * 8) + (mi_col * 8);
+  return framebuf + (stride * mi_row  << 3) + (mi_col << 3);
 }
 
 static VP9_DENOISER_DECISION perform_motion_compensation(VP9_DENOISER *denoiser,
@@ -195,24 +195,27 @@
                                                          PICK_MODE_CONTEXT *ctx,
                                                          int motion_magnitude,
                                                          int is_skin,
-                                                         int *zeromv_filter) {
-  int mv_col, mv_row;
+                                                         int *zeromv_filter,
+                                                         int consec_zeromv) {
   int sse_diff = ctx->zeromv_sse - ctx->newmv_sse;
   MV_REFERENCE_FRAME frame;
   MACROBLOCKD *filter_mbd = &mb->e_mbd;
   MODE_INFO *mi = filter_mbd->mi[0];
   MODE_INFO saved_mi;
-  int i, j;
+  int i;
   struct buf_2d saved_dst[MAX_MB_PLANE];
-  struct buf_2d saved_pre[MAX_MB_PLANE][2];  // 2 pre buffers
+  struct buf_2d saved_pre[MAX_MB_PLANE];
 
-  mv_col = ctx->best_sse_mv.as_mv.col;
-  mv_row = ctx->best_sse_mv.as_mv.row;
   frame = ctx->best_reference_frame;
-
   saved_mi = *mi;
 
-  if (is_skin && motion_magnitude > 0)
+  if (is_skin && (motion_magnitude > 0 || consec_zeromv < 4))
+    return COPY_BLOCK;
+
+  // Avoid denoising for small block (unless motion is small).
+  // Small blocks are selected in variance partition (before encoding) and
+  // will typically lie on moving areas.
+  if (motion_magnitude > 16 && bs <= BLOCK_8X8)
     return COPY_BLOCK;
 
   // If the best reference frame uses inter-prediction and there is enough of a
@@ -255,34 +258,31 @@
 
   // We will restore these after motion compensation.
   for (i = 0; i < MAX_MB_PLANE; ++i) {
-    for (j = 0; j < 2; ++j) {
-      saved_pre[i][j] = filter_mbd->plane[i].pre[j];
-    }
+    saved_pre[i] = filter_mbd->plane[i].pre[0];
     saved_dst[i] = filter_mbd->plane[i].dst;
   }
 
   // Set the pointers in the MACROBLOCKD to point to the buffers in the denoiser
   // struct.
-  for (j = 0; j < 2; ++j) {
-    filter_mbd->plane[0].pre[j].buf =
-        block_start(denoiser->running_avg_y[frame].y_buffer,
-                    denoiser->running_avg_y[frame].y_stride,
-                    mi_row, mi_col);
-    filter_mbd->plane[0].pre[j].stride =
-        denoiser->running_avg_y[frame].y_stride;
-    filter_mbd->plane[1].pre[j].buf =
-        block_start(denoiser->running_avg_y[frame].u_buffer,
-                    denoiser->running_avg_y[frame].uv_stride,
-                    mi_row, mi_col);
-    filter_mbd->plane[1].pre[j].stride =
-        denoiser->running_avg_y[frame].uv_stride;
-    filter_mbd->plane[2].pre[j].buf =
-        block_start(denoiser->running_avg_y[frame].v_buffer,
-                    denoiser->running_avg_y[frame].uv_stride,
-                    mi_row, mi_col);
-    filter_mbd->plane[2].pre[j].stride =
-        denoiser->running_avg_y[frame].uv_stride;
-  }
+  filter_mbd->plane[0].pre[0].buf =
+      block_start(denoiser->running_avg_y[frame].y_buffer,
+                  denoiser->running_avg_y[frame].y_stride,
+                  mi_row, mi_col);
+  filter_mbd->plane[0].pre[0].stride =
+      denoiser->running_avg_y[frame].y_stride;
+  filter_mbd->plane[1].pre[0].buf =
+       block_start(denoiser->running_avg_y[frame].u_buffer,
+                  denoiser->running_avg_y[frame].uv_stride,
+                  mi_row, mi_col);
+  filter_mbd->plane[1].pre[0].stride =
+      denoiser->running_avg_y[frame].uv_stride;
+  filter_mbd->plane[2].pre[0].buf =
+      block_start(denoiser->running_avg_y[frame].v_buffer,
+                  denoiser->running_avg_y[frame].uv_stride,
+                  mi_row, mi_col);
+  filter_mbd->plane[2].pre[0].stride =
+      denoiser->running_avg_y[frame].uv_stride;
+
   filter_mbd->plane[0].dst.buf =
       block_start(denoiser->mc_running_avg_y.y_buffer,
                   denoiser->mc_running_avg_y.y_stride,
@@ -299,30 +299,26 @@
                   mi_row, mi_col);
   filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.uv_stride;
 
-  vp9_build_inter_predictors_sby(filter_mbd, mv_row, mv_col, bs);
+  vp9_build_inter_predictors_sby(filter_mbd, mi_row, mi_col, bs);
 
   // Restore everything to its original state
   *mi = saved_mi;
   for (i = 0; i < MAX_MB_PLANE; ++i) {
-    for (j = 0; j < 2; ++j) {
-      filter_mbd->plane[i].pre[j] = saved_pre[i][j];
-    }
+    filter_mbd->plane[i].pre[0] = saved_pre[i];
     filter_mbd->plane[i].dst = saved_dst[i];
   }
 
-  mv_row = ctx->best_sse_mv.as_mv.row;
-  mv_col = ctx->best_sse_mv.as_mv.col;
-
   return FILTER_BLOCK;
 }
 
-void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
+void vp9_denoiser_denoise(VP9_COMP *cpi, MACROBLOCK *mb,
                           int mi_row, int mi_col, BLOCK_SIZE bs,
                           PICK_MODE_CONTEXT *ctx,
                           VP9_DENOISER_DECISION *denoiser_decision) {
   int mv_col, mv_row;
   int motion_magnitude = 0;
   int zeromv_filter = 0;
+  VP9_DENOISER *denoiser = &cpi->denoiser;
   VP9_DENOISER_DECISION decision = COPY_BLOCK;
   YV12_BUFFER_CONFIG avg = denoiser->running_avg_y[INTRA_FRAME];
   YV12_BUFFER_CONFIG mc_avg = denoiser->mc_running_avg_y;
@@ -331,21 +327,54 @@
                                           mi_row, mi_col);
   struct buf_2d src = mb->plane[0].src;
   int is_skin = 0;
+  int consec_zeromv = 0;
+  mv_col = ctx->best_sse_mv.as_mv.col;
+  mv_row = ctx->best_sse_mv.as_mv.row;
+  motion_magnitude = mv_row * mv_row + mv_col * mv_col;
 
-  if (bs <= BLOCK_32X32 && denoiser->denoising_level >= kDenLow) {
+  if (cpi->use_skin_detection &&
+      bs <= BLOCK_32X32 &&
+      denoiser->denoising_level >= kDenLow) {
+    int motion_level = (motion_magnitude < 16) ? 0 : 1;
+    // If motion for current block is small/zero, compute consec_zeromv for
+    // skin detection (early exit in skin detection is done for large
+    // consec_zeromv when current block has small/zero motion).
+    consec_zeromv = 0;
+    if (motion_level == 0) {
+      CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
+      VP9_COMMON * const cm = &cpi->common;
+      int j, i;
+      // Loop through the 8x8 sub-blocks.
+      const int bw = num_8x8_blocks_wide_lookup[BLOCK_64X64];
+      const int bh = num_8x8_blocks_high_lookup[BLOCK_64X64];
+      const int xmis = VPXMIN(cm->mi_cols - mi_col, bw);
+      const int ymis = VPXMIN(cm->mi_rows - mi_row, bh);
+      const int block_index = mi_row * cm->mi_cols + mi_col;
+      consec_zeromv = 100;
+      for (i = 0; i < ymis; i++) {
+        for (j = 0; j < xmis; j++) {
+          int bl_index = block_index + i * cm->mi_cols + j;
+          consec_zeromv = VPXMIN(cr->consec_zero_mv[bl_index], consec_zeromv);
+          // No need to keep checking 8x8 blocks if any of the sub-blocks
+          // has small consec_zeromv (since threshold for no_skin based on
+          // zero/small motion in skin detection is high, i.e, > 4).
+          if (consec_zeromv < 4) {
+            i = ymis;
+            j = xmis;
+          }
+        }
+      }
+    }
+    // TODO(marpan): Compute skin detection over sub-blocks.
     is_skin = vp9_compute_skin_block(mb->plane[0].src.buf,
                                      mb->plane[1].src.buf,
                                      mb->plane[2].src.buf,
                                      mb->plane[0].src.stride,
                                      mb->plane[1].src.stride,
                                      bs,
-                                     0,
-                                     0);
+                                     consec_zeromv,
+                                     motion_level);
   }
-
-  mv_col = ctx->best_sse_mv.as_mv.col;
-  mv_row = ctx->best_sse_mv.as_mv.row;
-  motion_magnitude = mv_row * mv_row + mv_col * mv_col;
   if (!is_skin &&
       denoiser->denoising_level == kDenHigh &&
       motion_magnitude < 16) {
@@ -360,7 +389,8 @@
                                            mi_row, mi_col, ctx,
                                            motion_magnitude,
                                            is_skin,
-                                           &zeromv_filter);
+                                           &zeromv_filter,
+                                           consec_zeromv);
 
   if (decision == FILTER_BLOCK) {
     decision = vp9_denoiser_filter(src.buf, src.stride,
@@ -420,11 +450,12 @@
                                     int resized) {
   // Copy source into denoised reference buffers on KEY_FRAME or
   // if the just encoded frame was resized.
-  if (frame_type == KEY_FRAME || resized != 0) {
+  if (frame_type == KEY_FRAME || resized != 0 || denoiser->reset) {
     int i;
     // Start at 1 so as not to overwrite the INTRA_FRAME
     for (i = 1; i < MAX_REF_FRAMES; ++i)
       copy_frame(&denoiser->running_avg_y[i], &src);
+    denoiser->reset = 0;
     return;
   }
 
@@ -537,6 +568,8 @@
   denoiser->increase_denoising = 0;
   denoiser->frame_buffer_initialized = 1;
   denoiser->denoising_level = kDenLow;
+  denoiser->prev_denoising_level = kDenLow;
+  denoiser->reset = 0;
   return 0;
 }
 
@@ -556,6 +589,12 @@
 void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser,
                                   int noise_level) {
   denoiser->denoising_level = noise_level;
+  if (denoiser->denoising_level > kDenLowLow &&
+      denoiser->prev_denoising_level == kDenLowLow)
+    denoiser->reset = 1;
+  else
+    denoiser->reset = 0;
+  denoiser->prev_denoising_level = denoiser->denoising_level;
 }
 
 #ifdef OUTPUT_YUV_DENOISED
diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h
index 9f13bd5..84189b4 100644
--- a/vp9/encoder/vp9_denoiser.h
+++ b/vp9/encoder/vp9_denoiser.h
@@ -40,7 +40,9 @@
   YV12_BUFFER_CONFIG last_source;
   int increase_denoising;
   int frame_buffer_initialized;
+  int reset;
   VP9_DENOISER_LEVEL denoising_level;
+  VP9_DENOISER_LEVEL prev_denoising_level;
 } VP9_DENOISER;
 
 struct VP9_COMP;
@@ -53,7 +55,7 @@
                                     int refresh_last_frame,
                                     int resized);
 
-void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb,
+void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb,
                           int mi_row, int mi_col, BLOCK_SIZE bs,
                           PICK_MODE_CONTEXT *ctx ,
                           VP9_DENOISER_DECISION *denoiser_decision);
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 9076b31..1d8bfa9 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1228,10 +1228,10 @@
   MODE_INFO *const mi = xd->mi[0];
   INTERP_FILTER filter_ref;
 
-  if (xd->up_available)
-    filter_ref = xd->mi[-xd->mi_stride]->interp_filter;
-  else if (xd->left_available)
-    filter_ref = xd->mi[-1]->interp_filter;
+  if (xd->above_mi)
+    filter_ref = xd->above_mi->interp_filter;
+  else if (xd->left_mi)
+    filter_ref = xd->left_mi->interp_filter;
   else
     filter_ref = EIGHTTAP;
 
@@ -1404,7 +1404,7 @@
     const int seg_ref_active = segfeature_active(&cm->seg, mi->segment_id,
                                                  SEG_LVL_REF_FRAME);
     if (!seg_ref_active) {
-      counts->intra_inter[vp9_get_intra_inter_context(xd)][inter_block]++;
+      counts->intra_inter[get_intra_inter_context(xd)][inter_block]++;
       // If the segment reference feature is enabled we have only a single
       // reference frame allowed for the segment so exclude it from
       // the reference frame counts used to work out probabilities.
@@ -2266,8 +2266,8 @@
                                     BLOCK_SIZE *max_block_size) {
   VP9_COMMON *const cm = &cpi->common;
   MODE_INFO **mi = xd->mi;
-  const int left_in_image = xd->left_available && mi[-1];
-  const int above_in_image = xd->up_available && mi[-xd->mi_stride];
+  const int left_in_image = !!xd->left_mi;
+  const int above_in_image = !!xd->above_mi;
   const int row8x8_remaining = tile->mi_row_end - mi_row;
   const int col8x8_remaining = tile->mi_col_end - mi_col;
   int bh, bw;
@@ -2362,7 +2362,7 @@
     }
   }
 
-  if (xd->left_available) {
+  if (xd->left_mi) {
     for (idy = 0; idy < mi_height; ++idy) {
       mi = xd->mi[idy * cm->mi_stride - 1];
       bs = mi ? mi->sb_type : bsize;
@@ -2371,7 +2371,7 @@
     }
   }
 
-  if (xd->up_available) {
+  if (xd->above_mi) {
     for (idx = 0; idx < mi_width; ++idx) {
       mi = xd->mi[idx - cm->mi_stride];
       bs = mi ? mi->sb_type : bsize;
@@ -4316,7 +4316,8 @@
       vp9_encode_intra_block_plane(x, VPXMAX(bsize, BLOCK_8X8), plane);
     if (output_enabled)
       sum_intra_stats(td->counts, mi);
-    vp9_tokenize_sb(cpi, td, t, !output_enabled, VPXMAX(bsize, BLOCK_8X8));
+    vp9_tokenize_sb(cpi, td, t, !output_enabled, seg_skip,
+                    VPXMAX(bsize, BLOCK_8X8));
   } else {
     int ref;
     const int is_compound = has_second_ref(mi);
@@ -4336,7 +4337,8 @@
                                     VPXMAX(bsize, BLOCK_8X8));
 
     vp9_encode_sb(x, VPXMAX(bsize, BLOCK_8X8));
-    vp9_tokenize_sb(cpi, td, t, !output_enabled, VPXMAX(bsize, BLOCK_8X8));
+    vp9_tokenize_sb(cpi, td, t, !output_enabled, seg_skip,
+                    VPXMAX(bsize, BLOCK_8X8));
   }
 
   if (output_enabled) {
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 01855ea..845f5aa 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -1687,6 +1687,7 @@
   cpi->common.buffer_pool = pool;
 
   cpi->rc.high_source_sad = 0;
+  cpi->rc.count_last_scene_change = 0;
 
   init_config(cpi, oxcf);
   vp9_rc_init(&cpi->oxcf, oxcf->pass, &cpi->rc);
@@ -2571,7 +2572,8 @@
              sizeof(cpi->interp_filter_selected[0]));
   }
 #if CONFIG_VP9_TEMPORAL_DENOISING
-  if (cpi->oxcf.noise_sensitivity > 0) {
+  if (cpi->oxcf.noise_sensitivity > 0 &&
+      cpi->denoiser.denoising_level > kDenLowLow) {
     vp9_denoiser_update_frame_info(&cpi->denoiser,
                                    *cpi->Source,
                                    cpi->common.frame_type,
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 10fd6c0..3e34c01 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -65,7 +65,7 @@
 
 #define NCOUNT_INTRA_THRESH 8192
 #define NCOUNT_INTRA_FACTOR 3
-#define NCOUNT_FRAME_II_THRESH 5.0
+
 
 #define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x) - 0.000001 : (x) + 0.000001)
 
@@ -115,7 +115,7 @@
 
     fprintf(fpfile, "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf"
             "%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf"
-            "%12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
+            "%12.4lf %12.4lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf\n",
             stats->frame,
             stats->weight,
             stats->intra_error,
@@ -126,6 +126,7 @@
             stats->pcnt_second_ref,
             stats->pcnt_neutral,
             stats->intra_skip_pct,
+            stats->intra_smooth_pct,
             stats->inactive_zone_rows,
             stats->inactive_zone_cols,
             stats->MVr,
@@ -165,6 +166,7 @@
   section->pcnt_second_ref = 0.0;
   section->pcnt_neutral = 0.0;
   section->intra_skip_pct = 0.0;
+  section->intra_smooth_pct = 0.0;
   section->inactive_zone_rows = 0.0;
   section->inactive_zone_cols = 0.0;
   section->MVr = 0.0;
@@ -193,6 +195,7 @@
   section->pcnt_second_ref += frame->pcnt_second_ref;
   section->pcnt_neutral += frame->pcnt_neutral;
   section->intra_skip_pct += frame->intra_skip_pct;
+  section->intra_smooth_pct += frame->intra_smooth_pct;
   section->inactive_zone_rows += frame->inactive_zone_rows;
   section->inactive_zone_cols += frame->inactive_zone_cols;
   section->MVr += frame->MVr;
@@ -219,6 +222,7 @@
   section->pcnt_second_ref -= frame->pcnt_second_ref;
   section->pcnt_neutral -= frame->pcnt_neutral;
   section->intra_skip_pct -= frame->intra_skip_pct;
+  section->intra_smooth_pct -= frame->intra_smooth_pct;
   section->inactive_zone_rows -= frame->inactive_zone_rows;
   section->inactive_zone_cols -= frame->inactive_zone_cols;
   section->MVr -= frame->MVr;
@@ -493,12 +497,12 @@
 // This threshold is used to track blocks where to all intents and purposes
 // the intra prediction error 0. Though the metric we test against
 // is technically a sse we are mainly interested in blocks where all the pixels
-// int he 8 bit domain have an error of <= 1 (where error = sse) so a
+// in the 8 bit domain have an error of <= 1 (where error = sse) so a
 // linear scaling for 10 and 12 bit gives similar results.
 #define UL_INTRA_THRESH 50
-#if CONFIG_VP9_HIGHBITDEPTH
 static int get_ul_intra_threshold(VP9_COMMON *cm) {
   int ret_val = UL_INTRA_THRESH;
+#if CONFIG_VP9_HIGHBITDEPTH
   if (cm->use_highbitdepth) {
     switch (cm->bit_depth) {
       case VPX_BITS_8:
@@ -515,9 +519,37 @@
                     "VPX_BITS_10 or VPX_BITS_12");
     }
   }
+#else
+  (void) cm;
+#endif  // CONFIG_VP9_HIGHBITDEPTH
   return ret_val;
 }
+
+#define SMOOTH_INTRA_THRESH 4000
+static int get_smooth_intra_threshold(VP9_COMMON *cm) {
+  int ret_val = SMOOTH_INTRA_THRESH;
+#if CONFIG_VP9_HIGHBITDEPTH
+  if (cm->use_highbitdepth) {
+    switch (cm->bit_depth) {
+      case VPX_BITS_8:
+        ret_val = SMOOTH_INTRA_THRESH;
+        break;
+      case VPX_BITS_10:
+        ret_val = SMOOTH_INTRA_THRESH >> 2;
+        break;
+      case VPX_BITS_12:
+        ret_val = SMOOTH_INTRA_THRESH >> 4;
+        break;
+      default:
+        assert(0 && "cm->bit_depth should be VPX_BITS_8, "
+                    "VPX_BITS_10 or VPX_BITS_12");
+    }
+  }
+#else
+  (void) cm;
 #endif  // CONFIG_VP9_HIGHBITDEPTH
+  return ret_val;
+}
 
 #define INVALID_ROW -1
 void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
@@ -545,6 +577,7 @@
   const int intrapenalty = INTRA_MODE_PENALTY;
   double neutral_count;
   int intra_skip_count = 0;
+  int intra_smooth_count = 0;
   int image_data_start_row = INVALID_ROW;
   int new_mv_count = 0;
   int sum_in_vectors = 0;
@@ -563,6 +596,7 @@
   double intra_factor;
   double brightness_factor;
   BufferPool *const pool = cm->buffer_pool;
+  MODE_INFO mi_above, mi_left;
 
   // First pass code requires valid last and new frame buffers.
   assert(new_yv12 != NULL);
@@ -695,6 +729,12 @@
                      mb_row << 1, num_8x8_blocks_high_lookup[bsize],
                      mb_col << 1, num_8x8_blocks_wide_lookup[bsize],
                      cm->mi_rows, cm->mi_cols);
+      // Are edges available for intra prediction?
+      // Since the firstpass does not populate the mi_grid_visible,
+      // above_mi/left_mi must be overwritten with a nonzero value when edges
+      // are available.  Required by vp9_predict_intra_block().
+      xd->above_mi = (mb_row != 0) ? &mi_above : NULL;
+      xd->left_mi  = (mb_col > tile.mi_col_start) ? &mi_left : NULL;
 
       // Do intra 16x16 prediction.
       x->skip_encode = 0;
@@ -709,15 +749,14 @@
       // domain). In natural videos this is uncommon, but it is much more
       // common in animations, graphics and screen content, so may be used
       // as a signal to detect these types of content.
-#if CONFIG_VP9_HIGHBITDEPTH
       if (this_error < get_ul_intra_threshold(cm)) {
-#else
-      if (this_error < UL_INTRA_THRESH) {
-#endif
         ++intra_skip_count;
       } else if ((mb_col > 0) && (image_data_start_row == INVALID_ROW)) {
         image_data_start_row = mb_row;
       }
+      if (this_error < get_smooth_intra_threshold(cm)) {
+        ++intra_smooth_count;
+      }
 
 #if CONFIG_VP9_HIGHBITDEPTH
       if (cm->use_highbitdepth) {
@@ -1083,6 +1122,7 @@
     fps.pcnt_second_ref = (double)second_ref_count / num_mbs;
     fps.pcnt_neutral = (double)neutral_count / num_mbs;
     fps.intra_skip_pct = (double)intra_skip_count / num_mbs;
+    fps.intra_smooth_pct = (double)intra_smooth_count / num_mbs;
     fps.inactive_zone_rows = (double)image_data_start_row;
     fps.inactive_zone_cols = (double)0;  // TODO(paulwilkins): fix
 
@@ -1371,11 +1411,12 @@
 }
 
 #define SR_DIFF_PART 0.0015
-#define MOTION_AMP_PART 0.003
 #define INTRA_PART 0.005
 #define DEFAULT_DECAY_LIMIT 0.75
 #define LOW_SR_DIFF_TRHESH 0.1
 #define SR_DIFF_MAX 128.0
+#define LOW_CODED_ERR_PER_MB 10.0
+#define NCOUNT_FRAME_II_THRESH 6.0
 
 static double get_sr_decay_rate(const VP9_COMP *cpi,
                                 const FIRSTPASS_STATS *frame) {
@@ -1386,12 +1427,15 @@
   double sr_decay = 1.0;
   double modified_pct_inter;
   double modified_pcnt_intra;
-  const double motion_amplitude_factor =
-    frame->pcnt_motion * ((frame->mvc_abs + frame->mvr_abs) / 2);
+  const double motion_amplitude_part =
+      frame->pcnt_motion *
+      ((frame->mvc_abs + frame->mvr_abs) /
+       (cpi->initial_height + cpi->initial_width));
 
   modified_pct_inter = frame->pcnt_inter;
-  if ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
-      (double)NCOUNT_FRAME_II_THRESH) {
+  if (((frame->coded_error / num_mbs) > LOW_CODED_ERR_PER_MB) &&
+      ((frame->intra_error / DOUBLE_DIVIDE_CHECK(frame->coded_error)) <
+       (double)NCOUNT_FRAME_II_THRESH)) {
     modified_pct_inter = frame->pcnt_inter - frame->pcnt_neutral;
   }
   modified_pcnt_intra = 100 * (1.0 - modified_pct_inter);
@@ -1400,7 +1444,7 @@
   if ((sr_diff > LOW_SR_DIFF_TRHESH)) {
     sr_diff = VPXMIN(sr_diff, SR_DIFF_MAX);
     sr_decay = 1.0 - (SR_DIFF_PART * sr_diff) -
-               (MOTION_AMP_PART * motion_amplitude_factor) -
+               motion_amplitude_part -
                (INTRA_PART * modified_pcnt_intra);
   }
   return VPXMAX(sr_decay, VPXMIN(DEFAULT_DECAY_LIMIT, modified_pct_inter));
@@ -1957,7 +2001,8 @@
     int int_lbq =
       (int)(vp9_convert_qindex_to_q(rc->last_boosted_qindex,
                                    cpi->common.bit_depth));
-    active_min_gf_interval = rc->min_gf_interval + VPXMIN(2, int_max_q / 200);
+    active_min_gf_interval =
+      rc->min_gf_interval + arf_active_or_kf + VPXMIN(2, int_max_q / 200);
     if (active_min_gf_interval > rc->max_gf_interval)
       active_min_gf_interval = rc->max_gf_interval;
 
@@ -1968,13 +2013,20 @@
       // bits to spare and are better with a smaller interval and smaller boost.
       // At high Q when there are few bits to spare we are better with a longer
       // interval to spread the cost of the GF.
-      active_max_gf_interval = 12 + VPXMIN(4, (int_lbq / 6));
+      active_max_gf_interval =
+        12 + arf_active_or_kf + VPXMIN(4, (int_lbq / 6));
 
       // We have: active_min_gf_interval <= rc->max_gf_interval
       if (active_max_gf_interval < active_min_gf_interval)
         active_max_gf_interval = active_min_gf_interval;
       else if (active_max_gf_interval > rc->max_gf_interval)
         active_max_gf_interval = rc->max_gf_interval;
+
+      // Would the active max drop us out just before the near the next kf?
+      if ((active_max_gf_interval <= rc->frames_to_key) &&
+          (active_max_gf_interval >=
+              (rc->frames_to_key - rc->min_gf_interval)))
+        active_max_gf_interval = rc->frames_to_key / 2;
     }
   }
 
@@ -2032,11 +2084,13 @@
     // Break out conditions.
     if (
       // Break at active_max_gf_interval unless almost totally static.
-      (i >= (active_max_gf_interval + arf_active_or_kf) &&
-            zero_motion_accumulator < 0.995) ||
+      ((i >= active_max_gf_interval) &&
+       (zero_motion_accumulator < 0.995)) ||
       (
         // Don't break out with a very short interval.
-        (i >= active_min_gf_interval + arf_active_or_kf) &&
+        (i >= active_min_gf_interval) &&
+        // If possible dont break very close to a kf
+        ((rc->frames_to_key - i) >= rc->min_gf_interval) &&
         (!flash_detected) &&
         ((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
          (abs_mv_in_out_accumulator > 3.0) ||
@@ -2782,6 +2836,7 @@
     // applied when combining MB error values for the frame.
     twopass->mb_av_energy =
       log(((this_frame.intra_error * 256.0) / num_mbs) + 1.0);
+    twopass->mb_smooth_pct = this_frame.intra_smooth_pct;
   }
 
   // Update the total stats remaining structure.
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index 5875a7b..7eb44fa 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -52,6 +52,7 @@
   double pcnt_second_ref;
   double pcnt_neutral;
   double intra_skip_pct;
+  double intra_smooth_pct;    // % of blocks that are smooth
   double inactive_zone_rows;  // Image mask rows top and bottom.
   double inactive_zone_cols;  // Image mask columns at left and right edges.
   double MVr;
@@ -107,6 +108,7 @@
   double modified_error_max;
   double modified_error_left;
   double mb_av_energy;
+  double mb_smooth_pct;
 
 #if CONFIG_FP_MB_STATS
   uint8_t *frame_mb_stats_buf;
diff --git a/vp9/encoder/vp9_mbgraph.c b/vp9/encoder/vp9_mbgraph.c
index 7ce86b4..3ae5b21 100644
--- a/vp9/encoder/vp9_mbgraph.c
+++ b/vp9/encoder/vp9_mbgraph.c
@@ -243,13 +243,16 @@
   int mb_y_offset = 0, arf_y_offset = 0, gld_y_offset = 0;
   MV gld_top_mv = {0, 0};
   MODE_INFO mi_local;
+  MODE_INFO mi_above, mi_left;
 
   vp9_zero(mi_local);
   // Set up limit values for motion vectors to prevent them extending outside
   // the UMV borders.
   x->mv_row_min     = -BORDER_MV_PIXELS_B16;
   x->mv_row_max     = (cm->mb_rows - 1) * 8 + BORDER_MV_PIXELS_B16;
-  xd->up_available  = 0;
+  // Signal to vp9_predict_intra_block() that above is not available
+  xd->above_mi = NULL;
+
   xd->plane[0].dst.stride  = buf->y_stride;
   xd->plane[0].pre[0].stride  = buf->y_stride;
   xd->plane[1].dst.stride = buf->uv_stride;
@@ -268,7 +271,8 @@
     // the UMV borders.
     x->mv_col_min      = -BORDER_MV_PIXELS_B16;
     x->mv_col_max      = (cm->mb_cols - 1) * 8 + BORDER_MV_PIXELS_B16;
-    xd->left_available = 0;
+    // Signal to vp9_predict_intra_block() that left is not available
+    xd->left_mi = NULL;
 
     for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) {
       MBGRAPH_MB_STATS *mb_stats = &stats->mb_stats[offset + mb_col];
@@ -280,14 +284,19 @@
       if (mb_col == 0) {
         gld_top_mv = gld_left_mv;
       }
-      xd->left_available = 1;
+      // Signal to vp9_predict_intra_block() that left is available
+      xd->left_mi = &mi_left;
+
       mb_y_in_offset    += 16;
       gld_y_in_offset   += 16;
       arf_y_in_offset   += 16;
       x->mv_col_min     -= 16;
       x->mv_col_max     -= 16;
     }
-    xd->up_available = 1;
+
+    // Signal to vp9_predict_intra_block() that above is available
+    xd->above_mi = &mi_above;
+
     mb_y_offset     += buf->y_stride * 16;
     gld_y_offset    += golden_ref->y_stride * 16;
     if (alt_ref)
diff --git a/vp9/encoder/vp9_noise_estimate.c b/vp9/encoder/vp9_noise_estimate.c
index d505629..10ea010 100644
--- a/vp9/encoder/vp9_noise_estimate.c
+++ b/vp9/encoder/vp9_noise_estimate.c
@@ -91,7 +91,7 @@
   } else {
     if (ne->value > ne->thresh)
       noise_level = kMedium;
-    else if (ne->value > (ne->thresh >> 1))
+    else if (ne->value > ((9 * ne->thresh) >> 4))
       noise_level = kLow;
     else
       noise_level = kLowLow;
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index 3ea2ccd..2e27f94 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -701,10 +701,9 @@
     }
   }
 
-  if (*skippable == 0) {
-    *rate <<= (2 + VP9_PROB_COST_SHIFT);
-    *rate += (eob_cost << VP9_PROB_COST_SHIFT);
-  }
+  // If skippable is set, rate gets clobbered later.
+  *rate <<= (2 + VP9_PROB_COST_SHIFT);
+  *rate += (eob_cost << VP9_PROB_COST_SHIFT);
 }
 #endif
 
@@ -906,6 +905,7 @@
   VP9_COMP *cpi;
   MACROBLOCK *x;
   PREDICTION_MODE mode;
+  int skippable;
   int rate;
   int64_t dist;
 };
@@ -941,13 +941,9 @@
 
   if (plane == 0) {
     int64_t this_sse = INT64_MAX;
-    int is_skippable;
     // TODO(jingning): This needs further refactoring.
-    block_yrd(cpi, x, &rate, &dist, &is_skippable, &this_sse, 0,
+    block_yrd(cpi, x, &rate, &dist, &args->skippable, &this_sse, 0,
               bsize_tx, VPXMIN(tx_size, TX_16X16));
-    x->skip_txfm[0] = is_skippable;
-    // TODO(jingning): Skip is signalled per prediciton block not per tx block.
-    rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), is_skippable);
   } else {
     unsigned int var = 0;
     unsigned int sse = 0;
@@ -1011,14 +1007,14 @@
   MODE_INFO *const mi = xd->mi[0];
   RD_COST this_rdc, best_rdc;
   PREDICTION_MODE this_mode;
-  struct estimate_block_intra_args args = { cpi, x, DC_PRED, 0, 0 };
+  struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0, 0 };
   const TX_SIZE intra_tx_size =
       VPXMIN(max_txsize_lookup[bsize],
              tx_mode_to_biggest_tx_size[cpi->common.tx_mode]);
   MODE_INFO *const mic = xd->mi[0];
   int *bmode_costs;
-  const MODE_INFO *above_mi = xd->mi[-xd->mi_stride];
-  const MODE_INFO *left_mi = xd->left_available ? xd->mi[-1] : NULL;
+  const MODE_INFO *above_mi = xd->above_mi;
+  const MODE_INFO *left_mi = xd->left_mi;
   const PREDICTION_MODE A = vp9_above_block_mode(mic, above_mi, 0);
   const PREDICTION_MODE L = vp9_left_block_mode(mic, left_mi, 0);
   bmode_costs = cpi->y_mode_costs[A][L];
@@ -1036,11 +1032,19 @@
   // mode tests.
   for (this_mode = DC_PRED; this_mode <= H_PRED; ++this_mode) {
     args.mode = this_mode;
+    args.skippable = 1;
     args.rate = 0;
     args.dist = 0;
     mi->tx_size = intra_tx_size;
     vp9_foreach_transformed_block_in_plane(xd, bsize, 0,
                                            estimate_block_intra, &args);
+    if (args.skippable) {
+      x->skip_txfm[0] = SKIP_TXFM_AC_DC;
+      args.rate = vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 1);
+    } else {
+      x->skip_txfm[0] = SKIP_TXFM_NONE;
+      args.rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 0);
+    }
     this_rdc.rate = args.rate;
     this_rdc.dist = args.dist;
     this_rdc.rate += bmode_costs[this_mode];
@@ -1242,10 +1246,10 @@
   x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
   x->skip = 0;
 
-  if (xd->up_available)
-    filter_ref = xd->mi[-xd->mi_stride]->interp_filter;
-  else if (xd->left_available)
-    filter_ref = xd->mi[-1]->interp_filter;
+  if (xd->above_mi)
+    filter_ref = xd->above_mi->interp_filter;
+  else if (xd->left_mi)
+    filter_ref = xd->left_mi->interp_filter;
   else
     filter_ref = cm->interp_filter;
 
@@ -1270,7 +1274,10 @@
   }
 
 #if CONFIG_VP9_TEMPORAL_DENOISING
-  vp9_denoiser_reset_frame_stats(ctx);
+  if (cpi->oxcf.noise_sensitivity > 0 &&
+      cpi->denoiser.denoising_level > kDenLowLow) {
+    vp9_denoiser_reset_frame_stats(ctx);
+  }
 #endif
 
   if (cpi->rc.frames_since_golden == 0 && !cpi->use_svc) {
@@ -1642,7 +1649,8 @@
     }
 
 #if CONFIG_VP9_TEMPORAL_DENOISING
-    if (cpi->oxcf.noise_sensitivity > 0) {
+    if (cpi->oxcf.noise_sensitivity > 0 &&
+        cpi->denoiser.denoising_level > kDenLowLow) {
       vp9_denoiser_update_frame_stats(mi, sse_y, this_mode, ctx);
       // Keep track of zero_last cost.
       if (ref_frame == LAST_FRAME && frame_mv[this_mode][ref_frame].as_int == 0)
@@ -1706,7 +1714,7 @@
       ((best_rdc.rdcost == INT64_MAX ||
       (!x->skip && best_rdc.rdcost > inter_mode_thresh &&
        bsize <= cpi->sf.max_intra_bsize)))) {
-    struct estimate_block_intra_args args = { cpi, x, DC_PRED, 0, 0 };
+    struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0, 0 };
     int i;
     TX_SIZE best_intra_tx_size = TX_SIZES;
     TX_SIZE intra_tx_size =
@@ -1756,11 +1764,21 @@
       mi->mode = this_mode;
       mi->ref_frame[0] = INTRA_FRAME;
       args.mode = this_mode;
+      args.skippable = 1;
       args.rate = 0;
       args.dist = 0;
       mi->tx_size = intra_tx_size;
       vp9_foreach_transformed_block_in_plane(xd, bsize, 0,
                                              estimate_block_intra, &args);
+      // Check skip cost here since skippable is not set for for uv, this
+      // mirrors the behavior used by inter
+      if (args.skippable) {
+        x->skip_txfm[0] = SKIP_TXFM_AC_DC;
+        args.rate = vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 1);
+      } else {
+        x->skip_txfm[0] = SKIP_TXFM_NONE;
+        args.rate += vp9_cost_bit(vp9_get_skip_prob(&cpi->common, xd), 0);
+      }
       // Inter and intra RD will mismatch in scale for non-screen content.
       if (cpi->oxcf.content == VP9E_CONTENT_SCREEN) {
         if (x->color_sensitivity[0])
@@ -1823,10 +1841,12 @@
 
 #if CONFIG_VP9_TEMPORAL_DENOISING
   if (cpi->oxcf.noise_sensitivity > 0 &&
-      cpi->resize_pending == 0) {
+      cpi->resize_pending == 0 &&
+      cpi->denoiser.denoising_level > kDenLowLow &&
+      cpi->denoiser.reset == 0) {
     VP9_DENOISER_DECISION decision = COPY_BLOCK;
-    vp9_denoiser_denoise(&cpi->denoiser, x, mi_row, mi_col,
-                         VPXMAX(BLOCK_8X8, bsize), ctx, &decision);
+    vp9_denoiser_denoise(cpi, x, mi_row, mi_col, VPXMAX(BLOCK_8X8, bsize),
+                         ctx, &decision);
     // If INTRA or GOLDEN reference was selected, re-evaluate ZEROMV on denoised
     // result. Only do this under noise conditions, and if rdcost of ZEROMV on
     // original source is not significantly higher than rdcost of best mode.
diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c
index 61bb35e..dab7f67 100644
--- a/vp9/encoder/vp9_ratectrl.c
+++ b/vp9/encoder/vp9_ratectrl.c
@@ -133,7 +133,7 @@
     kf_high_m[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
     arfgf_low[i] = get_minq_index(maxq, 0.0000015, -0.0009, 0.30, bit_depth);
     arfgf_high[i] = get_minq_index(maxq, 0.0000021, -0.00125, 0.55, bit_depth);
-    inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.90, bit_depth);
+    inter[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
     rtc[i] = get_minq_index(maxq, 0.00000271, -0.00113, 0.70, bit_depth);
   }
 }
@@ -621,15 +621,16 @@
 
   if (cpi->common.frame_type == KEY_FRAME) {
     active_worst_quality = curr_frame == 0 ? rc->worst_quality
-                                           : rc->last_q[KEY_FRAME] * 2;
+                                           : rc->last_q[KEY_FRAME] << 1;
   } else {
     if (!rc->is_src_frame_alt_ref &&
         (cpi->refresh_golden_frame || cpi->refresh_alt_ref_frame)) {
-      active_worst_quality =  curr_frame == 1 ? rc->last_q[KEY_FRAME] * 5 / 4
+      active_worst_quality =  curr_frame == 1 ? rc->last_q[KEY_FRAME] * 5 >> 2
                                               : rc->last_q[INTER_FRAME];
     } else {
-      active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] * 2
-                                             : rc->last_q[INTER_FRAME] * 2;
+      active_worst_quality = curr_frame == 1 ? rc->last_q[KEY_FRAME] << 1 :
+          VPXMIN(rc->last_q[INTER_FRAME] << 1,
+                (rc->avg_frame_qindex[INTER_FRAME] * 3 >> 1));
     }
   }
   return VPXMIN(active_worst_quality, rc->worst_quality);
@@ -662,7 +663,7 @@
                    VPXMIN(rc->avg_frame_qindex[INTER_FRAME],
                           rc->avg_frame_qindex[KEY_FRAME]) :
                    rc->avg_frame_qindex[INTER_FRAME];
-  active_worst_quality = VPXMIN(rc->worst_quality, ambient_qp * 5 / 4);
+  active_worst_quality = VPXMIN(rc->worst_quality, ambient_qp * 5 >> 2);
   if (rc->buffer_level > rc->optimal_buffer_level) {
     // Adjust down.
     // Maximum limit for down adjustment, ~30%.
@@ -811,8 +812,8 @@
   return q;
 }
 
-static int get_active_cq_level(const RATE_CONTROL *rc,
-                               const VP9EncoderConfig *const oxcf) {
+static int get_active_cq_level_one_pass(
+    const RATE_CONTROL *rc, const VP9EncoderConfig *const oxcf) {
   static const double cq_adjust_threshold = 0.1;
   int active_cq_level = oxcf->cq_level;
   if (oxcf->rc_mode == VPX_CQ &&
@@ -825,13 +826,36 @@
   return active_cq_level;
 }
 
+#define SMOOTH_PCT_MIN  0.1
+#define SMOOTH_PCT_DIV  0.05
+static int get_active_cq_level_two_pass(
+    const TWO_PASS *twopass, const RATE_CONTROL *rc,
+    const VP9EncoderConfig *const oxcf) {
+  static const double cq_adjust_threshold = 0.1;
+  int active_cq_level = oxcf->cq_level;
+  if (oxcf->rc_mode == VPX_CQ) {
+    if (twopass->mb_smooth_pct > SMOOTH_PCT_MIN) {
+      active_cq_level -= (int)((twopass->mb_smooth_pct - SMOOTH_PCT_MIN) /
+          SMOOTH_PCT_DIV);
+      active_cq_level = VPXMAX(active_cq_level, 0);
+    }
+    if (rc->total_target_bits > 0) {
+      const double x = (double)rc->total_actual_bits / rc->total_target_bits;
+      if (x < cq_adjust_threshold) {
+        active_cq_level = (int)(active_cq_level * x / cq_adjust_threshold);
+      }
+    }
+  }
+  return active_cq_level;
+}
+
 static int rc_pick_q_and_bounds_one_pass_vbr(const VP9_COMP *cpi,
                                              int *bottom_index,
                                              int *top_index) {
   const VP9_COMMON *const cm = &cpi->common;
   const RATE_CONTROL *const rc = &cpi->rc;
   const VP9EncoderConfig *const oxcf = &cpi->oxcf;
-  const int cq_level = get_active_cq_level(rc, oxcf);
+  const int cq_level = get_active_cq_level_one_pass(rc, oxcf);
   int active_best_quality;
   int active_worst_quality = calc_active_worst_quality_one_pass_vbr(cpi);
   int q;
@@ -881,9 +905,12 @@
     // Use the lower of active_worst_quality and recent
     // average Q as basis for GF/ARF best Q limit unless last frame was
     // a key frame.
-    if (rc->frames_since_key > 1 &&
-        rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
-      q = rc->avg_frame_qindex[INTER_FRAME];
+    if (rc->frames_since_key > 1) {
+      if (rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
+        q = rc->avg_frame_qindex[INTER_FRAME];
+      } else {
+        q = active_worst_quality;
+      }
     } else {
       q = rc->avg_frame_qindex[KEY_FRAME];
     }
@@ -1017,7 +1044,7 @@
   const RATE_CONTROL *const rc = &cpi->rc;
   const VP9EncoderConfig *const oxcf = &cpi->oxcf;
   const GF_GROUP *gf_group = &cpi->twopass.gf_group;
-  const int cq_level = get_active_cq_level(rc, oxcf);
+  const int cq_level = get_active_cq_level_two_pass(&cpi->twopass, rc, oxcf);
   int active_best_quality;
   int active_worst_quality = cpi->twopass.active_worst_quality;
   int q;
@@ -2047,8 +2074,8 @@
     // for cases where there is small change from content that is completely
     // static.
     if (cpi->oxcf.rc_mode == VPX_VBR) {
-      min_thresh = 30000;
-      thresh = 2.0f;
+      min_thresh = 60000;
+      thresh = 2.1f;
     }
     if (avg_sad >
         VPXMAX(min_thresh, (unsigned int)(rc->avg_source_sad  * thresh)) &&
@@ -2057,20 +2084,25 @@
     else
       rc->high_source_sad = 0;
     if (avg_sad > 0 || cpi->oxcf.rc_mode == VPX_CBR)
-      rc->avg_source_sad = (rc->avg_source_sad + avg_sad) >> 1;
+      rc->avg_source_sad = (3 * rc->avg_source_sad + avg_sad) >> 2;
     // For VBR, under scene change/high content change, force golden refresh.
     if (cpi->oxcf.rc_mode == VPX_VBR &&
         rc->high_source_sad &&
-        cpi->refresh_golden_frame == 0 &&
+        rc->count_last_scene_change > 4 &&
         cpi->ext_refresh_frame_flags_pending == 0) {
       int target;
       cpi->refresh_golden_frame = 1;
+      rc->gfu_boost = DEFAULT_GF_BOOST >> 1;
+      rc->baseline_gf_interval = VPXMIN(20,
+          VPXMAX(10, rc->baseline_gf_interval));
       rc->frames_till_gf_update_due = rc->baseline_gf_interval;
       if (rc->frames_till_gf_update_due > rc->frames_to_key)
         rc->frames_till_gf_update_due = rc->frames_to_key;
-      rc->gfu_boost = DEFAULT_GF_BOOST;
       target = calc_pframe_target_size_one_pass_vbr(cpi);
       vp9_rc_set_frame_target(cpi, target);
+      rc->count_last_scene_change = 0;
+    } else {
+      rc->count_last_scene_change++;
     }
   }
 }
diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h
index 3df909c..4cd4b12 100644
--- a/vp9/encoder/vp9_ratectrl.h
+++ b/vp9/encoder/vp9_ratectrl.h
@@ -161,6 +161,7 @@
 
   uint64_t avg_source_sad;
   int high_source_sad;
+  int count_last_scene_change;
 } RATE_CONTROL;
 
 struct VP9_COMP;
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 508c596..a304182 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -2460,10 +2460,10 @@
 
   if (pred_filter_search) {
     INTERP_FILTER af = SWITCHABLE, lf = SWITCHABLE;
-    if (xd->up_available)
-      af = xd->mi[-xd->mi_stride]->interp_filter;
-    if (xd->left_available)
-      lf = xd->mi[-1]->interp_filter;
+    if (xd->above_mi)
+      af = xd->above_mi->interp_filter;
+    if (xd->left_mi)
+      lf = xd->left_mi->interp_filter;
 
     if ((this_mode != NEWMV) || (af == lf))
       best_filter = af;
diff --git a/vp9/encoder/vp9_resize.c b/vp9/encoder/vp9_resize.c
index 63f0ce2..307a112 100644
--- a/vp9/encoder/vp9_resize.c
+++ b/vp9/encoder/vp9_resize.c
@@ -446,7 +446,7 @@
                              int length,
                              uint8_t *output,
                              int olength,
-                             uint8_t *buf) {
+                             uint8_t *otmp) {
   int steps;
   if (length == olength) {
     memcpy(output, input, sizeof(output[0]) * length);
@@ -457,16 +457,10 @@
   if (steps > 0) {
     int s;
     uint8_t *out = NULL;
-    uint8_t *tmpbuf = NULL;
-    uint8_t *otmp, *otmp2;
+    uint8_t *otmp2;
     int filteredlength = length;
-    if (!tmpbuf) {
-      tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
-      if (tmpbuf == NULL) return;
-      otmp = tmpbuf;
-    } else {
-      otmp = buf;
-    }
+
+    assert(otmp != NULL);
     otmp2 = otmp + get_down2_length(length, 1);
     for (s = 0; s < steps; ++s) {
       const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -484,8 +478,6 @@
     if (filteredlength != olength) {
       interpolate(out, filteredlength, output, olength);
     }
-    if (tmpbuf)
-      free(tmpbuf);
   } else {
     interpolate(input, length, output, olength);
   }
@@ -521,25 +513,29 @@
   uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
   uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
                                       (width < height ? height : width));
-  uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
-  if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+  uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * height);
+  uint8_t *arrbuf2 = (uint8_t *)malloc(sizeof(uint8_t) * height2);
+  if (intbuf == NULL || tmpbuf == NULL ||
+      arrbuf == NULL || arrbuf2 == NULL)
+    goto Error;
   assert(width > 0);
   assert(height > 0);
   assert(width2 > 0);
   assert(height2 > 0);
   for (i = 0; i < height; ++i)
     resize_multistep(input + in_stride * i, width,
-                        intbuf + width2 * i, width2, tmpbuf);
+                     intbuf + width2 * i, width2, tmpbuf);
   for (i = 0; i < width2; ++i) {
     fill_col_to_arr(intbuf + i, width2, height, arrbuf);
-    resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
-    fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
+    resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf);
+    fill_arr_to_col(output + i, out_stride, height2, arrbuf2);
   }
 
  Error:
   free(intbuf);
   free(tmpbuf);
   free(arrbuf);
+  free(arrbuf2);
 }
 
 #if CONFIG_VP9_HIGHBITDEPTH
@@ -742,7 +738,7 @@
                                     int length,
                                     uint16_t *output,
                                     int olength,
-                                    uint16_t *buf,
+                                    uint16_t *otmp,
                                     int bd) {
   int steps;
   if (length == olength) {
@@ -754,16 +750,10 @@
   if (steps > 0) {
     int s;
     uint16_t *out = NULL;
-    uint16_t *tmpbuf = NULL;
-    uint16_t *otmp, *otmp2;
+    uint16_t *otmp2;
     int filteredlength = length;
-    if (!tmpbuf) {
-      tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
-      if (tmpbuf == NULL) return;
-      otmp = tmpbuf;
-    } else {
-      otmp = buf;
-    }
+
+    assert(otmp != NULL);
     otmp2 = otmp + get_down2_length(length, 1);
     for (s = 0; s < steps; ++s) {
       const int proj_filteredlength = get_down2_length(filteredlength, 1);
@@ -781,8 +771,6 @@
     if (filteredlength != olength) {
       highbd_interpolate(out, filteredlength, output, olength, bd);
     }
-    if (tmpbuf)
-      free(tmpbuf);
   } else {
     highbd_interpolate(input, length, output, olength, bd);
   }
@@ -821,24 +809,28 @@
   uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
   uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
                                         (width < height ? height : width));
-  uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
-  if (intbuf == NULL || tmpbuf == NULL || arrbuf == NULL) goto Error;
+  uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * height);
+  uint16_t *arrbuf2 = (uint16_t *)malloc(sizeof(uint16_t) * height2);
+  if (intbuf == NULL || tmpbuf == NULL ||
+      arrbuf == NULL || arrbuf2 == NULL)
+    goto Error;
   for (i = 0; i < height; ++i) {
     highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
                             intbuf + width2 * i, width2, tmpbuf, bd);
   }
   for (i = 0; i < width2; ++i) {
     highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
-    highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
+    highbd_resize_multistep(arrbuf, height, arrbuf2, height2, tmpbuf,
                             bd);
     highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
-                           arrbuf + height);
+                           arrbuf2);
   }
 
  Error:
   free(intbuf);
   free(tmpbuf);
   free(arrbuf);
+  free(arrbuf2);
 }
 #endif  // CONFIG_VP9_HIGHBITDEPTH
 
diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c
index ee1d08a..edec755 100644
--- a/vp9/encoder/vp9_tokenize.c
+++ b/vp9/encoder/vp9_tokenize.c
@@ -18,7 +18,6 @@
 #include "vp9/common/vp9_entropy.h"
 #include "vp9/common/vp9_pred_common.h"
 #include "vp9/common/vp9_scan.h"
-#include "vp9/common/vp9_seg_common.h"
 
 #include "vp9/encoder/vp9_cost.h"
 #include "vp9/encoder/vp9_encoder.h"
@@ -354,12 +353,6 @@
   ++counts[token];
 }
 
-static INLINE int get_tx_eob(const struct segmentation *seg, int segment_id,
-                             TX_SIZE tx_size) {
-  const int eob_max = 16 << (tx_size << 1);
-  return segfeature_active(seg, segment_id, SEG_LVL_SKIP) ? 0 : eob_max;
-}
-
 static void tokenize_b(int plane, int block, BLOCK_SIZE plane_bsize,
                        TX_SIZE tx_size, void *arg) {
   struct tokenize_b_args* const args = arg;
@@ -378,7 +371,6 @@
   int eob = p->eobs[block];
   const PLANE_TYPE type = get_plane_type(plane);
   const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
-  const int segment_id = mi->segment_id;
   const int16_t *scan, *nb;
   const scan_order *so;
   const int ref = is_inter_block(mi);
@@ -389,7 +381,7 @@
   unsigned int (*const eob_branch)[COEFF_CONTEXTS] =
       td->counts->eob_branch[tx_size][type][ref];
   const uint8_t *const band = get_band_translate(tx_size);
-  const int seg_eob = get_tx_eob(&cpi->common.seg, segment_id, tx_size);
+  const int tx_eob = 16 << (tx_size << 1);
   int16_t token;
   EXTRABIT extra;
   int aoff, loff;
@@ -426,7 +418,7 @@
     ++c;
     pt = get_coef_context(nb, token_cache, c);
   }
-  if (c < seg_eob) {
+  if (c < tx_eob) {
     ++eob_branch[band[c]][pt];
     add_token_no_extra(&t, coef_probs[band[c]][pt], EOB_TOKEN,
                        counts[band[c]][pt]);
@@ -481,24 +473,26 @@
 }
 
 void vp9_tokenize_sb(VP9_COMP *cpi, ThreadData *td, TOKENEXTRA **t,
-                     int dry_run, BLOCK_SIZE bsize) {
-  VP9_COMMON *const cm = &cpi->common;
+                     int dry_run, int seg_skip, BLOCK_SIZE bsize) {
   MACROBLOCK *const x = &td->mb;
   MACROBLOCKD *const xd = &x->e_mbd;
   MODE_INFO *const mi = xd->mi[0];
   const int ctx = vp9_get_skip_context(xd);
-  const int skip_inc = !segfeature_active(&cm->seg, mi->segment_id,
-                                          SEG_LVL_SKIP);
   struct tokenize_b_args arg = {cpi, td, t};
+
+  if (seg_skip) {
+    assert(mi->skip);
+  }
+
   if (mi->skip) {
-    if (!dry_run)
-      td->counts->skip[ctx][1] += skip_inc;
+    if (!dry_run && !seg_skip)
+      ++td->counts->skip[ctx][1];
     reset_skip_context(xd, bsize);
     return;
   }
 
   if (!dry_run) {
-    td->counts->skip[ctx][0] += skip_inc;
+    ++td->counts->skip[ctx][0];
     vp9_foreach_transformed_block(xd, bsize, tokenize_b, &arg);
   } else {
     vp9_foreach_transformed_block(xd, bsize, set_entropy_context_b, &arg);
diff --git a/vp9/encoder/vp9_tokenize.h b/vp9/encoder/vp9_tokenize.h
index fad7988..1caab2a 100644
--- a/vp9/encoder/vp9_tokenize.h
+++ b/vp9/encoder/vp9_tokenize.h
@@ -51,7 +51,8 @@
 struct ThreadData;
 
 void vp9_tokenize_sb(struct VP9_COMP *cpi, struct ThreadData *td,
-                     TOKENEXTRA **t, int dry_run, BLOCK_SIZE bsize);
+                     TOKENEXTRA **t, int dry_run, int seg_skip,
+                     BLOCK_SIZE bsize);
 
 typedef struct {
   const vpx_prob *prob;
diff --git a/vpx_dsp/avg.c b/vpx_dsp/avg.c
index d3695a9..2e9dfd4 100644
--- a/vpx_dsp/avg.c
+++ b/vpx_dsp/avg.c
@@ -62,7 +62,7 @@
   coeff[5] = c3 - c7;
 }
 
-void vpx_hadamard_8x8_c(int16_t const *src_diff, int src_stride,
+void vpx_hadamard_8x8_c(const int16_t *src_diff, int src_stride,
                         int16_t *coeff) {
   int idx;
   int16_t buffer[64];
@@ -85,12 +85,12 @@
 }
 
 // In place 16x16 2D Hadamard transform
-void vpx_hadamard_16x16_c(int16_t const *src_diff, int src_stride,
+void vpx_hadamard_16x16_c(const int16_t *src_diff, int src_stride,
                           int16_t *coeff) {
   int idx;
   for (idx = 0; idx < 4; ++idx) {
     // src_diff: 9 bit, dynamic range [-255, 255]
-    int16_t const *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
+    const int16_t *src_ptr = src_diff + (idx >> 1) * 8 * src_stride
                                 + (idx & 0x01) * 8;
     vpx_hadamard_8x8_c(src_ptr, src_stride, coeff + idx * 64);
   }
@@ -130,7 +130,7 @@
 
 // Integer projection onto row vectors.
 // height: value range {16, 32, 64}.
-void vpx_int_pro_row_c(int16_t hbuf[16], uint8_t const *ref,
+void vpx_int_pro_row_c(int16_t hbuf[16], const uint8_t *ref,
                        const int ref_stride, const int height) {
   int idx;
   const int norm_factor = height >> 1;
@@ -147,7 +147,7 @@
 }
 
 // width: value range {16, 32, 64}.
-int16_t vpx_int_pro_col_c(uint8_t const *ref, const int width) {
+int16_t vpx_int_pro_col_c(const uint8_t *ref, const int width) {
   int idx;
   int16_t sum = 0;
   // sum: 14 bit, dynamic range [0, 16320]
@@ -159,7 +159,7 @@
 // ref: [0 - 510]
 // src: [0 - 510]
 // bwl: {2, 3, 4}
-int vpx_vector_var_c(int16_t const *ref, int16_t const *src,
+int vpx_vector_var_c(const int16_t *ref, const int16_t *src,
                      const int bwl) {
   int i;
   int width = 4 << bwl;
diff --git a/vpx_dsp/fwd_txfm.c b/vpx_dsp/fwd_txfm.c
index 7baaa8b..a5802e1 100644
--- a/vpx_dsp/fwd_txfm.c
+++ b/vpx_dsp/fwd_txfm.c
@@ -85,7 +85,6 @@
       sum += input[r * stride + c];
 
   output[0] = sum << 1;
-  output[1] = 0;
 }
 
 void vpx_fdct8x8_c(const int16_t *input, tran_low_t *final_output, int stride) {
@@ -182,7 +181,6 @@
       sum += input[r * stride + c];
 
   output[0] = sum;
-  output[1] = 0;
 }
 
 void vpx_fdct16x16_c(const int16_t *input, tran_low_t *output, int stride) {
@@ -367,13 +365,12 @@
 
 void vpx_fdct16x16_1_c(const int16_t *input, tran_low_t *output, int stride) {
   int r, c;
-  tran_low_t sum = 0;
+  int sum = 0;
   for (r = 0; r < 16; ++r)
     for (c = 0; c < 16; ++c)
       sum += input[r * stride + c];
 
-  output[0] = sum >> 1;
-  output[1] = 0;
+  output[0] = (tran_low_t)(sum >> 1);
 }
 
 static INLINE tran_high_t dct_32_round(tran_high_t input) {
@@ -771,13 +768,12 @@
 
 void vpx_fdct32x32_1_c(const int16_t *input, tran_low_t *output, int stride) {
   int r, c;
-  tran_low_t sum = 0;
+  int sum = 0;
   for (r = 0; r < 32; ++r)
     for (c = 0; c < 32; ++c)
       sum += input[r * stride + c];
 
-  output[0] = sum >> 3;
-  output[1] = 0;
+  output[0] = (tran_low_t)(sum >> 3);
 }
 
 #if CONFIG_VP9_HIGHBITDEPTH
diff --git a/vpx_dsp/mips/fwd_dct32x32_msa.c b/vpx_dsp/mips/fwd_dct32x32_msa.c
index 2115a34..f29c14b 100644
--- a/vpx_dsp/mips/fwd_dct32x32_msa.c
+++ b/vpx_dsp/mips/fwd_dct32x32_msa.c
@@ -933,23 +933,21 @@
 }
 
 void vpx_fdct32x32_1_msa(const int16_t *input, int16_t *out, int32_t stride) {
-  out[1] = 0;
-
-  out[0] = LD_HADD(input, stride);
-  out[0] += LD_HADD(input + 8, stride);
-  out[0] += LD_HADD(input + 16, stride);
-  out[0] += LD_HADD(input + 24, stride);
-  out[0] += LD_HADD(input + 32 * 8, stride);
-  out[0] += LD_HADD(input + 32 * 8 + 8, stride);
-  out[0] += LD_HADD(input + 32 * 8 + 16, stride);
-  out[0] += LD_HADD(input + 32 * 8 + 24, stride);
-  out[0] += LD_HADD(input + 32 * 16, stride);
-  out[0] += LD_HADD(input + 32 * 16 + 8, stride);
-  out[0] += LD_HADD(input + 32 * 16 + 16, stride);
-  out[0] += LD_HADD(input + 32 * 16 + 24, stride);
-  out[0] += LD_HADD(input + 32 * 24, stride);
-  out[0] += LD_HADD(input + 32 * 24 + 8, stride);
-  out[0] += LD_HADD(input + 32 * 24 + 16, stride);
-  out[0] += LD_HADD(input + 32 * 24 + 24, stride);
-  out[0] >>= 3;
+  int sum = LD_HADD(input, stride);
+  sum += LD_HADD(input + 8, stride);
+  sum += LD_HADD(input + 16, stride);
+  sum += LD_HADD(input + 24, stride);
+  sum += LD_HADD(input + 32 * 8, stride);
+  sum += LD_HADD(input + 32 * 8 + 8, stride);
+  sum += LD_HADD(input + 32 * 8 + 16, stride);
+  sum += LD_HADD(input + 32 * 8 + 24, stride);
+  sum += LD_HADD(input + 32 * 16, stride);
+  sum += LD_HADD(input + 32 * 16 + 8, stride);
+  sum += LD_HADD(input + 32 * 16 + 16, stride);
+  sum += LD_HADD(input + 32 * 16 + 24, stride);
+  sum += LD_HADD(input + 32 * 24, stride);
+  sum += LD_HADD(input + 32 * 24 + 8, stride);
+  sum += LD_HADD(input + 32 * 24 + 16, stride);
+  sum += LD_HADD(input + 32 * 24 + 24, stride);
+  out[0] = (int16_t)(sum >> 3);
 }
diff --git a/vpx_dsp/mips/fwd_txfm_msa.c b/vpx_dsp/mips/fwd_txfm_msa.c
index f66dd5f..0dd141f 100644
--- a/vpx_dsp/mips/fwd_txfm_msa.c
+++ b/vpx_dsp/mips/fwd_txfm_msa.c
@@ -237,11 +237,9 @@
 }
 
 void vpx_fdct16x16_1_msa(const int16_t *input, int16_t *out, int32_t stride) {
-  out[1] = 0;
-
-  out[0] = LD_HADD(input, stride);
-  out[0] += LD_HADD(input + 8, stride);
-  out[0] += LD_HADD(input + 16 * 8, stride);
-  out[0] += LD_HADD(input + 16 * 8 + 8, stride);
-  out[0] >>= 1;
+  int sum = LD_HADD(input, stride);
+  sum += LD_HADD(input + 8, stride);
+  sum += LD_HADD(input + 16 * 8, stride);
+  sum += LD_HADD(input + 16 * 8 + 8, stride);
+  out[0] = (int16_t)(sum >> 1);
 }
diff --git a/vpx_dsp/vpx_dsp_rtcd_defs.pl b/vpx_dsp/vpx_dsp_rtcd_defs.pl
index a648e45..779c41a 100644
--- a/vpx_dsp/vpx_dsp_rtcd_defs.pl
+++ b/vpx_dsp/vpx_dsp_rtcd_defs.pl
@@ -924,9 +924,9 @@
     $vpx_idct32x32_135_add_msa=vpx_idct32x32_1024_add_msa;
 
     add_proto qw/void vpx_idct32x32_34_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
-    specialize qw/vpx_idct32x32_34_add sse2 neon_asm dspr2 msa/, "$ssse3_x86_64_x86inc";
+    specialize qw/vpx_idct32x32_34_add sse2 neon dspr2 msa/, "$ssse3_x86_64_x86inc";
     # Need to add 34 eob idct32x32 neon implementation.
-    $vpx_idct32x32_34_add_neon_asm=vpx_idct32x32_1024_add_neon;
+    $vpx_idct32x32_34_add_neon=vpx_idct32x32_1024_add_neon;
 
     add_proto qw/void vpx_idct32x32_1_add/, "const tran_low_t *input, uint8_t *dest, int dest_stride";
     specialize qw/vpx_idct32x32_1_add sse2 neon dspr2 msa/;
@@ -1001,22 +1001,22 @@
     specialize qw/vpx_highbd_minmax_8x8/;
   }
 
-  add_proto qw/void vpx_hadamard_8x8/, "int16_t const *src_diff, int src_stride, int16_t *coeff";
+  add_proto qw/void vpx_hadamard_8x8/, "const int16_t *src_diff, int src_stride, int16_t *coeff";
   specialize qw/vpx_hadamard_8x8 sse2/, "$ssse3_x86_64_x86inc";
 
-  add_proto qw/void vpx_hadamard_16x16/, "int16_t const *src_diff, int src_stride, int16_t *coeff";
+  add_proto qw/void vpx_hadamard_16x16/, "const int16_t *src_diff, int src_stride, int16_t *coeff";
   specialize qw/vpx_hadamard_16x16 sse2/;
 
   add_proto qw/int vpx_satd/, "const int16_t *coeff, int length";
   specialize qw/vpx_satd sse2 neon/;
 
-  add_proto qw/void vpx_int_pro_row/, "int16_t *hbuf, uint8_t const *ref, const int ref_stride, const int height";
+  add_proto qw/void vpx_int_pro_row/, "int16_t *hbuf, const uint8_t *ref, const int ref_stride, const int height";
   specialize qw/vpx_int_pro_row sse2 neon/;
 
-  add_proto qw/int16_t vpx_int_pro_col/, "uint8_t const *ref, const int width";
+  add_proto qw/int16_t vpx_int_pro_col/, "const uint8_t *ref, const int width";
   specialize qw/vpx_int_pro_col sse2 neon/;
 
-  add_proto qw/int vpx_vector_var/, "int16_t const *ref, int16_t const *src, const int bwl";
+  add_proto qw/int vpx_vector_var/, "const int16_t *ref, const int16_t *src, const int bwl";
   specialize qw/vpx_vector_var neon sse2/;
 }  # CONFIG_VP9_ENCODER || CONFIG_VP10_ENCODER
 
diff --git a/vpx_dsp/x86/fwd_txfm_sse2.c b/vpx_dsp/x86/fwd_txfm_sse2.c
index bca72e8..e4deeec 100644
--- a/vpx_dsp/x86/fwd_txfm_sse2.c
+++ b/vpx_dsp/x86/fwd_txfm_sse2.c
@@ -40,7 +40,7 @@
 
   in1 = _mm_add_epi32(tmp, in0);
   in0 = _mm_slli_epi32(in1, 1);
-  store_output(&in0, output);
+  output[0] = (tran_low_t)_mm_cvtsi128_si32(in0);
 }
 
 void vpx_fdct8x8_1_sse2(const int16_t *input, tran_low_t *output, int stride) {
@@ -80,7 +80,7 @@
   in0 = _mm_srli_si128(sum, 8);
 
   in1 = _mm_add_epi32(sum, in0);
-  store_output(&in1, output);
+  output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
 }
 
 void vpx_fdct16x16_1_sse2(const int16_t *input, tran_low_t *output,
@@ -91,40 +91,39 @@
   int i;
 
   for (i = 0; i < 2; ++i) {
-    input += 8 * i;
-    in0  = _mm_load_si128((const __m128i *)(input +  0 * stride));
-    in1  = _mm_load_si128((const __m128i *)(input +  1 * stride));
-    in2  = _mm_load_si128((const __m128i *)(input +  2 * stride));
-    in3  = _mm_load_si128((const __m128i *)(input +  3 * stride));
+    in0  = _mm_load_si128((const __m128i *)(input + 0 * stride + 0));
+    in1  = _mm_load_si128((const __m128i *)(input + 0 * stride + 8));
+    in2  = _mm_load_si128((const __m128i *)(input + 1 * stride + 0));
+    in3  = _mm_load_si128((const __m128i *)(input + 1 * stride + 8));
 
     u0 = _mm_add_epi16(in0, in1);
     u1 = _mm_add_epi16(in2, in3);
     sum = _mm_add_epi16(sum, u0);
 
-    in0  = _mm_load_si128((const __m128i *)(input +  4 * stride));
-    in1  = _mm_load_si128((const __m128i *)(input +  5 * stride));
-    in2  = _mm_load_si128((const __m128i *)(input +  6 * stride));
-    in3  = _mm_load_si128((const __m128i *)(input +  7 * stride));
+    in0  = _mm_load_si128((const __m128i *)(input + 2 * stride + 0));
+    in1  = _mm_load_si128((const __m128i *)(input + 2 * stride + 8));
+    in2  = _mm_load_si128((const __m128i *)(input + 3 * stride + 0));
+    in3  = _mm_load_si128((const __m128i *)(input + 3 * stride + 8));
 
     sum = _mm_add_epi16(sum, u1);
     u0  = _mm_add_epi16(in0, in1);
     u1  = _mm_add_epi16(in2, in3);
     sum = _mm_add_epi16(sum, u0);
 
-    in0  = _mm_load_si128((const __m128i *)(input +  8 * stride));
-    in1  = _mm_load_si128((const __m128i *)(input +  9 * stride));
-    in2  = _mm_load_si128((const __m128i *)(input + 10 * stride));
-    in3  = _mm_load_si128((const __m128i *)(input + 11 * stride));
+    in0  = _mm_load_si128((const __m128i *)(input + 4 * stride + 0));
+    in1  = _mm_load_si128((const __m128i *)(input + 4 * stride + 8));
+    in2  = _mm_load_si128((const __m128i *)(input + 5 * stride + 0));
+    in3  = _mm_load_si128((const __m128i *)(input + 5 * stride + 8));
 
     sum = _mm_add_epi16(sum, u1);
     u0  = _mm_add_epi16(in0, in1);
     u1  = _mm_add_epi16(in2, in3);
     sum = _mm_add_epi16(sum, u0);
 
-    in0  = _mm_load_si128((const __m128i *)(input + 12 * stride));
-    in1  = _mm_load_si128((const __m128i *)(input + 13 * stride));
-    in2  = _mm_load_si128((const __m128i *)(input + 14 * stride));
-    in3  = _mm_load_si128((const __m128i *)(input + 15 * stride));
+    in0  = _mm_load_si128((const __m128i *)(input + 6 * stride + 0));
+    in1  = _mm_load_si128((const __m128i *)(input + 6 * stride + 8));
+    in2  = _mm_load_si128((const __m128i *)(input + 7 * stride + 0));
+    in3  = _mm_load_si128((const __m128i *)(input + 7 * stride + 8));
 
     sum = _mm_add_epi16(sum, u1);
     u0  = _mm_add_epi16(in0, in1);
@@ -132,6 +131,7 @@
     sum = _mm_add_epi16(sum, u0);
 
     sum = _mm_add_epi16(sum, u1);
+    input += 8 * stride;
   }
 
   u0  = _mm_setzero_si128();
@@ -149,7 +149,7 @@
 
   in1 = _mm_add_epi32(sum, in0);
   in1 = _mm_srai_epi32(in1, 1);
-  store_output(&in1, output);
+  output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
 }
 
 void vpx_fdct32x32_1_sse2(const int16_t *input, tran_low_t *output,
@@ -221,7 +221,7 @@
 
   in1 = _mm_add_epi32(sum, in0);
   in1 = _mm_srai_epi32(in1, 3);
-  store_output(&in1, output);
+  output[0] = (tran_low_t)_mm_cvtsi128_si32(in1);
 }
 
 #define DCT_HIGH_BIT_DEPTH 0
diff --git a/vpx_ports/mem_ops.h b/vpx_ports/mem_ops.h
index d4a3d77..1f8f914 100644
--- a/vpx_ports/mem_ops.h
+++ b/vpx_ports/mem_ops.h
@@ -168,8 +168,8 @@
 static VPX_INLINE void mem_put_be16(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >> 8) & 0xff;
-  mem[1] = (val >> 0) & 0xff;
+  mem[0] = (MAU_T)((val >> 8) & 0xff);
+  mem[1] = (MAU_T)((val >> 0) & 0xff);
 }
 
 #undef  mem_put_be24
@@ -177,9 +177,9 @@
 static VPX_INLINE void mem_put_be24(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >> 16) & 0xff;
-  mem[1] = (val >>  8) & 0xff;
-  mem[2] = (val >>  0) & 0xff;
+  mem[0] = (MAU_T)((val >> 16) & 0xff);
+  mem[1] = (MAU_T)((val >>  8) & 0xff);
+  mem[2] = (MAU_T)((val >>  0) & 0xff);
 }
 
 #undef  mem_put_be32
@@ -187,10 +187,10 @@
 static VPX_INLINE void mem_put_be32(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >> 24) & 0xff;
-  mem[1] = (val >> 16) & 0xff;
-  mem[2] = (val >>  8) & 0xff;
-  mem[3] = (val >>  0) & 0xff;
+  mem[0] = (MAU_T)((val >> 24) & 0xff);
+  mem[1] = (MAU_T)((val >> 16) & 0xff);
+  mem[2] = (MAU_T)((val >>  8) & 0xff);
+  mem[3] = (MAU_T)((val >>  0) & 0xff);
 }
 
 #undef  mem_put_le16
@@ -198,8 +198,8 @@
 static VPX_INLINE void mem_put_le16(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >>  0) & 0xff;
-  mem[1] = (val >>  8) & 0xff;
+  mem[0] = (MAU_T)((val >> 0) & 0xff);
+  mem[1] = (MAU_T)((val >> 8) & 0xff);
 }
 
 #undef  mem_put_le24
@@ -207,9 +207,9 @@
 static VPX_INLINE void mem_put_le24(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >>  0) & 0xff;
-  mem[1] = (val >>  8) & 0xff;
-  mem[2] = (val >> 16) & 0xff;
+  mem[0] = (MAU_T)((val >>  0) & 0xff);
+  mem[1] = (MAU_T)((val >>  8) & 0xff);
+  mem[2] = (MAU_T)((val >> 16) & 0xff);
 }
 
 #undef  mem_put_le32
@@ -217,10 +217,10 @@
 static VPX_INLINE void mem_put_le32(void *vmem, MEM_VALUE_T val) {
   MAU_T *mem = (MAU_T *)vmem;
 
-  mem[0] = (val >>  0) & 0xff;
-  mem[1] = (val >>  8) & 0xff;
-  mem[2] = (val >> 16) & 0xff;
-  mem[3] = (val >> 24) & 0xff;
+  mem[0] = (MAU_T)((val >>  0) & 0xff);
+  mem[1] = (MAU_T)((val >>  8) & 0xff);
+  mem[2] = (MAU_T)((val >> 16) & 0xff);
+  mem[3] = (MAU_T)((val >> 24) & 0xff);
 }
 
 #endif  // VPX_PORTS_MEM_OPS_H_
diff --git a/vpx_ports/mem_ops_aligned.h b/vpx_ports/mem_ops_aligned.h
index c16111f..46f6173 100644
--- a/vpx_ports/mem_ops_aligned.h
+++ b/vpx_ports/mem_ops_aligned.h
@@ -28,8 +28,8 @@
  * could redefine these macros.
  */
 #define swap_endian_16(val,raw) do {\
-    val = ((raw>>8) & 0x00ff) \
-          | ((raw<<8) & 0xff00);\
+    val = (uint16_t)(((raw>>8) & 0x00ff) \
+          | ((raw<<8) & 0xff00));\
   } while(0)
 #define swap_endian_32(val,raw) do {\
     val = ((raw>>24) & 0x000000ff) \
diff --git a/webmdec.cc b/webmdec.cc
index f541cfe..81150aa 100644
--- a/webmdec.cc
+++ b/webmdec.cc
@@ -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 {
 
@@ -164,7 +164,7 @@
       }
       get_new_block = true;
     }
-    if (status) {
+    if (status || block_entry == NULL) {
       return -1;
     }
     if (get_new_block) {
diff --git a/webmenc.cc b/webmenc.cc
index d41e700..caf4391 100644
--- a/webmenc.cc
+++ b/webmenc.cc
@@ -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;