shithub: libvpx

Download patch

ref: 74aaa2389ec056f9dd8631eeed42fe7a757daf32
parent: 5572ab1d027afd6a990774daa9ae720ae3c4282d
author: Tom Finegan <tomfinegan@google.com>
date: Thu Mar 24 09:12:51 EDT 2016

third_party: Roll libwebm snapshot.

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

Change-Id: I49c1d6dbfab2855af886dc8af53cf6cf5ca382c2

diff: cannot open b/third_party/libwebm/common//null: file does not exist: 'b/third_party/libwebm/common//null' diff: cannot open b/third_party/libwebm/mkvmuxer//null: file does not exist: 'b/third_party/libwebm/mkvmuxer//null' diff: cannot open b/third_party/libwebm/mkvparser//null: file does not exist: 'b/third_party/libwebm/mkvparser//null'
--- a/examples.mk
+++ b/examples.mk
@@ -36,22 +36,31 @@
                 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.
 UTILS-$(CONFIG_DECODERS)    += vpxdec.c
@@ -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
--- 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)
--- a/test/test.mk
+++ b/test/test.mk
@@ -59,10 +59,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
--- 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
+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)
--- 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: 5c50e310e7050192b952fe588186fd1dadc08b6e
 License: BSD
 License File: LICENSE.txt
 
@@ -7,4 +7,4 @@
 libwebm is used to handle WebM container I/O.
 
 Local Changes:
-* <none>
+* Android.mk modified to build Libwebm for Android within Libvpx.
--- a/third_party/libwebm/RELEASE.TXT
+++ /dev/null
@@ -1,34 +1,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
--- /dev/null
+++ b/third_party/libwebm/common/file_util.cc
@@ -1,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
--- /dev/null
+++ b/third_party/libwebm/common/file_util.h
@@ -1,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
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.cc
@@ -1,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
--- /dev/null
+++ b/third_party/libwebm/common/hdr_util.h
@@ -1,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_
--- /dev/null
+++ b/third_party/libwebm/common/webmids.h
@@ -1,0 +1,184 @@
+// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#ifndef COMMON_WEBMIDS_H_
+#define COMMON_WEBMIDS_H_
+
+namespace libwebm {
+
+enum MkvId {
+  kMkvEBML = 0x1A45DFA3,
+  kMkvEBMLVersion = 0x4286,
+  kMkvEBMLReadVersion = 0x42F7,
+  kMkvEBMLMaxIDLength = 0x42F2,
+  kMkvEBMLMaxSizeLength = 0x42F3,
+  kMkvDocType = 0x4282,
+  kMkvDocTypeVersion = 0x4287,
+  kMkvDocTypeReadVersion = 0x4285,
+  kMkvVoid = 0xEC,
+  kMkvSignatureSlot = 0x1B538667,
+  kMkvSignatureAlgo = 0x7E8A,
+  kMkvSignatureHash = 0x7E9A,
+  kMkvSignaturePublicKey = 0x7EA5,
+  kMkvSignature = 0x7EB5,
+  kMkvSignatureElements = 0x7E5B,
+  kMkvSignatureElementList = 0x7E7B,
+  kMkvSignedElement = 0x6532,
+  // segment
+  kMkvSegment = 0x18538067,
+  // Meta Seek Information
+  kMkvSeekHead = 0x114D9B74,
+  kMkvSeek = 0x4DBB,
+  kMkvSeekID = 0x53AB,
+  kMkvSeekPosition = 0x53AC,
+  // Segment Information
+  kMkvInfo = 0x1549A966,
+  kMkvTimecodeScale = 0x2AD7B1,
+  kMkvDuration = 0x4489,
+  kMkvDateUTC = 0x4461,
+  kMkvTitle = 0x7BA9,
+  kMkvMuxingApp = 0x4D80,
+  kMkvWritingApp = 0x5741,
+  // Cluster
+  kMkvCluster = 0x1F43B675,
+  kMkvTimecode = 0xE7,
+  kMkvPrevSize = 0xAB,
+  kMkvBlockGroup = 0xA0,
+  kMkvBlock = 0xA1,
+  kMkvBlockDuration = 0x9B,
+  kMkvReferenceBlock = 0xFB,
+  kMkvLaceNumber = 0xCC,
+  kMkvSimpleBlock = 0xA3,
+  kMkvBlockAdditions = 0x75A1,
+  kMkvBlockMore = 0xA6,
+  kMkvBlockAddID = 0xEE,
+  kMkvBlockAdditional = 0xA5,
+  kMkvDiscardPadding = 0x75A2,
+  // Track
+  kMkvTracks = 0x1654AE6B,
+  kMkvTrackEntry = 0xAE,
+  kMkvTrackNumber = 0xD7,
+  kMkvTrackUID = 0x73C5,
+  kMkvTrackType = 0x83,
+  kMkvFlagEnabled = 0xB9,
+  kMkvFlagDefault = 0x88,
+  kMkvFlagForced = 0x55AA,
+  kMkvFlagLacing = 0x9C,
+  kMkvDefaultDuration = 0x23E383,
+  kMkvMaxBlockAdditionID = 0x55EE,
+  kMkvName = 0x536E,
+  kMkvLanguage = 0x22B59C,
+  kMkvCodecID = 0x86,
+  kMkvCodecPrivate = 0x63A2,
+  kMkvCodecName = 0x258688,
+  kMkvCodecDelay = 0x56AA,
+  kMkvSeekPreRoll = 0x56BB,
+  // video
+  kMkvVideo = 0xE0,
+  kMkvFlagInterlaced = 0x9A,
+  kMkvStereoMode = 0x53B8,
+  kMkvAlphaMode = 0x53C0,
+  kMkvPixelWidth = 0xB0,
+  kMkvPixelHeight = 0xBA,
+  kMkvPixelCropBottom = 0x54AA,
+  kMkvPixelCropTop = 0x54BB,
+  kMkvPixelCropLeft = 0x54CC,
+  kMkvPixelCropRight = 0x54DD,
+  kMkvDisplayWidth = 0x54B0,
+  kMkvDisplayHeight = 0x54BA,
+  kMkvDisplayUnit = 0x54B2,
+  kMkvAspectRatioType = 0x54B3,
+  kMkvFrameRate = 0x2383E3,
+  // end video
+  // colour
+  kMkvColour = 0x55B0,
+  kMkvMatrixCoefficients = 0x55B1,
+  kMkvBitsPerChannel = 0x55B2,
+  kMkvChromaSubsamplingHorz = 0x55B3,
+  kMkvChromaSubsamplingVert = 0x55B4,
+  kMkvCbSubsamplingHorz = 0x55B5,
+  kMkvCbSubsamplingVert = 0x55B6,
+  kMkvChromaSitingHorz = 0x55B7,
+  kMkvChromaSitingVert = 0x55B8,
+  kMkvRange = 0x55B9,
+  kMkvTransferCharacteristics = 0x55BA,
+  kMkvPrimaries = 0x55BB,
+  kMkvMaxCLL = 0x55BC,
+  kMkvMaxFALL = 0x55BD,
+  // mastering metadata
+  kMkvMasteringMetadata = 0x55D0,
+  kMkvPrimaryRChromaticityX = 0x55D1,
+  kMkvPrimaryRChromaticityY = 0x55D2,
+  kMkvPrimaryGChromaticityX = 0x55D3,
+  kMkvPrimaryGChromaticityY = 0x55D4,
+  kMkvPrimaryBChromaticityX = 0x55D5,
+  kMkvPrimaryBChromaticityY = 0x55D6,
+  kMkvWhitePointChromaticityX = 0x55D7,
+  kMkvWhitePointChromaticityY = 0x55D8,
+  kMkvLuminanceMax = 0x55D9,
+  kMkvLuminanceMin = 0x55DA,
+  // end mastering metadata
+  // end colour
+  // audio
+  kMkvAudio = 0xE1,
+  kMkvSamplingFrequency = 0xB5,
+  kMkvOutputSamplingFrequency = 0x78B5,
+  kMkvChannels = 0x9F,
+  kMkvBitDepth = 0x6264,
+  // end audio
+  // ContentEncodings
+  kMkvContentEncodings = 0x6D80,
+  kMkvContentEncoding = 0x6240,
+  kMkvContentEncodingOrder = 0x5031,
+  kMkvContentEncodingScope = 0x5032,
+  kMkvContentEncodingType = 0x5033,
+  kMkvContentCompression = 0x5034,
+  kMkvContentCompAlgo = 0x4254,
+  kMkvContentCompSettings = 0x4255,
+  kMkvContentEncryption = 0x5035,
+  kMkvContentEncAlgo = 0x47E1,
+  kMkvContentEncKeyID = 0x47E2,
+  kMkvContentSignature = 0x47E3,
+  kMkvContentSigKeyID = 0x47E4,
+  kMkvContentSigAlgo = 0x47E5,
+  kMkvContentSigHashAlgo = 0x47E6,
+  kMkvContentEncAESSettings = 0x47E7,
+  kMkvAESSettingsCipherMode = 0x47E8,
+  kMkvAESSettingsCipherInitData = 0x47E9,
+  // end ContentEncodings
+  // Cueing Data
+  kMkvCues = 0x1C53BB6B,
+  kMkvCuePoint = 0xBB,
+  kMkvCueTime = 0xB3,
+  kMkvCueTrackPositions = 0xB7,
+  kMkvCueTrack = 0xF7,
+  kMkvCueClusterPosition = 0xF1,
+  kMkvCueBlockNumber = 0x5378,
+  // Chapters
+  kMkvChapters = 0x1043A770,
+  kMkvEditionEntry = 0x45B9,
+  kMkvChapterAtom = 0xB6,
+  kMkvChapterUID = 0x73C4,
+  kMkvChapterStringUID = 0x5654,
+  kMkvChapterTimeStart = 0x91,
+  kMkvChapterTimeEnd = 0x92,
+  kMkvChapterDisplay = 0x80,
+  kMkvChapString = 0x85,
+  kMkvChapLanguage = 0x437C,
+  kMkvChapCountry = 0x437E,
+  // Tags
+  kMkvTags = 0x1254C367,
+  kMkvTag = 0x7373,
+  kMkvSimpleTag = 0x67C8,
+  kMkvTagName = 0x45A3,
+  kMkvTagString = 0x4487
+};
+
+}  // namespace libwebm
+
+#endif  // COMMON_WEBMIDS_H_
--- a/third_party/libwebm/mkvmuxer.cpp
+++ /dev/null
@@ -1,3277 +1,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
--- a/third_party/libwebm/mkvmuxer.hpp
+++ /dev/null
@@ -1,1492 +1,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 MKVMUXER_HPP
-#define MKVMUXER_HPP
-
-#include "mkvmuxertypes.hpp"
-
-// For a description of the WebM elements see
-// http://www.webmproject.org/code/specs/container/.
-
-namespace mkvparser {
-class IMkvReader;
-}  // end namespace
-
-namespace mkvmuxer {
-
-class MkvWriter;
-class Segment;
-
-const uint64 kMaxTrackNumber = 126;
-
-///////////////////////////////////////////////////////////////
-// Interface used by the mkvmuxer to write out the Mkv data.
-class IMkvWriter {
- public:
-  // Writes out |len| bytes of |buf|. Returns 0 on success.
-  virtual int32 Write(const void* buf, uint32 len) = 0;
-
-  // Returns the offset of the output position from the beginning of the
-  // output.
-  virtual int64 Position() const = 0;
-
-  // Set the current File position. Returns 0 on success.
-  virtual int32 Position(int64 position) = 0;
-
-  // Returns true if the writer is seekable.
-  virtual bool Seekable() const = 0;
-
-  // Element start notification. Called whenever an element identifier is about
-  // to be written to the stream. |element_id| is the element identifier, and
-  // |position| is the location in the WebM stream where the first octet of the
-  // element identifier will be written.
-  // Note: the |MkvId| enumeration in webmids.hpp defines element values.
-  virtual void ElementStartNotify(uint64 element_id, int64 position) = 0;
-
- protected:
-  IMkvWriter();
-  virtual ~IMkvWriter();
-
- private:
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter);
-};
-
-// Writes out the EBML header for a WebM file. This function must be called
-// before any other libwebm writing functions are called.
-bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version);
-
-// 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);
-
-///////////////////////////////////////////////////////////////
-// Class to hold data the will be written to a block.
-class Frame {
- public:
-  Frame();
-  ~Frame();
-
-  // Sets this frame's contents based on |frame|. Returns true on success. On
-  // failure, this frame's existing contents may be lost.
-  bool CopyFrom(const Frame& frame);
-
-  // Copies |frame| data into |frame_|. Returns true on success.
-  bool Init(const uint8* frame, uint64 length);
-
-  // Copies |additional| data into |additional_|. Returns true on success.
-  bool AddAdditionalData(const uint8* additional, uint64 length, uint64 add_id);
-
-  // Returns true if the frame has valid parameters.
-  bool IsValid() const;
-
-  // Returns true if the frame can be written as a SimpleBlock based on current
-  // 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_; }
-  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) {
-    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_; }
-  bool reference_block_timestamp_set() const {
-    return reference_block_timestamp_set_;
-  }
-
- private:
-  // Id of the Additional data.
-  uint64 add_id_;
-
-  // Pointer to additional data. Owned by this class.
-  uint8* additional_;
-
-  // Length of the additional data.
-  uint64 additional_length_;
-
-  // Duration of the frame in nanoseconds.
-  uint64 duration_;
-
-  // Pointer to the data. Owned by this class.
-  uint8* frame_;
-
-  // Flag telling if the data should set the key flag of a block.
-  bool is_key_;
-
-  // Length of the data.
-  uint64 length_;
-
-  // Mkv track number the data is associated with.
-  uint64 track_number_;
-
-  // Timestamp of the data in nanoseconds.
-  uint64 timestamp_;
-
-  // Discard padding for the frame.
-  int64 discard_padding_;
-
-  // Reference block timestamp.
-  int64 reference_block_timestamp_;
-
-  // Flag indicating if |reference_block_timestamp_| has been set.
-  bool reference_block_timestamp_set_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Frame);
-};
-
-///////////////////////////////////////////////////////////////
-// Class to hold one cue point in a Cues element.
-class CuePoint {
- public:
-  CuePoint();
-  ~CuePoint();
-
-  // Returns the size in bytes for the entire CuePoint element.
-  uint64 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_output_block_number(bool output_block_number) {
-    output_block_number_ = output_block_number;
-  }
-  bool output_block_number() const { return output_block_number_; }
-
- private:
-  // Returns the size in bytes for the payload of the CuePoint element.
-  uint64 PayloadSize() const;
-
-  // Absolute timecode according to the segment time base.
-  uint64 time_;
-
-  // The Track element associated with the CuePoint.
-  uint64 track_;
-
-  // The position of the Cluster containing the Block.
-  uint64 cluster_pos_;
-
-  // Number of the Block within the Cluster, starting from 1.
-  uint64 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.
-  bool output_block_number_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(CuePoint);
-};
-
-///////////////////////////////////////////////////////////////
-// Cues element.
-class Cues {
- public:
-  Cues();
-  ~Cues();
-
-  // Adds a cue point to the Cues element. Returns true on success.
-  bool AddCue(CuePoint* cue);
-
-  // Returns the cue point by index. Returns NULL if there is no cue point
-  // match.
-  CuePoint* GetCueByIndex(int32 index) const;
-
-  // Returns the total size of the Cues element
-  uint64 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_; }
-  void set_output_block_number(bool output_block_number) {
-    output_block_number_ = output_block_number;
-  }
-  bool output_block_number() const { return output_block_number_; }
-
- private:
-  // Number of allocated elements in |cue_entries_|.
-  int32 cue_entries_capacity_;
-
-  // Number of CuePoints in |cue_entries_|.
-  int32 cue_entries_size_;
-
-  // CuePoint list.
-  CuePoint** cue_entries_;
-
-  // 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.
-  bool output_block_number_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues);
-};
-
-///////////////////////////////////////////////////////////////
-// ContentEncAESSettings element
-class ContentEncAESSettings {
- public:
-  enum { kCTR = 1 };
-
-  ContentEncAESSettings();
-  ~ContentEncAESSettings() {}
-
-  // Returns the size in bytes for the ContentEncAESSettings element.
-  uint64 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_; }
-
- private:
-  // Returns the size in bytes for the payload of the ContentEncAESSettings
-  // element.
-  uint64 PayloadSize() const;
-
-  // Sub elements
-  uint64 cipher_mode_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
-};
-
-///////////////////////////////////////////////////////////////
-// ContentEncoding element
-// Elements used to describe if the track data has been encrypted or
-// compressed with zlib or header stripping.
-// Currently only whole frames can be encrypted with AES. This dictates that
-// ContentEncodingOrder will be 0, ContentEncodingScope will be 1,
-// ContentEncodingType will be 1, and ContentEncAlgo will be 5.
-class ContentEncoding {
- public:
-  ContentEncoding();
-  ~ContentEncoding();
-
-  // Sets the content encryption id. Copies |length| bytes from |id| to
-  // |enc_key_id_|. Returns true on success.
-  bool SetEncryptionID(const uint8* id, uint64 length);
-
-  // Returns the size in bytes for the ContentEncoding element.
-  uint64 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_; }
-  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;
-
-  // Returns the size in bytes for the encryption elements.
-  uint64 EncryptionSize() const;
-
-  // Track element names
-  uint64 enc_algo_;
-  uint8* enc_key_id_;
-  uint64 encoding_order_;
-  uint64 encoding_scope_;
-  uint64 encoding_type_;
-
-  // ContentEncAESSettings element.
-  ContentEncAESSettings enc_aes_settings_;
-
-  // Size of the ContentEncKeyID data in bytes.
-  uint64 enc_key_id_length_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
-};
-
-///////////////////////////////////////////////////////////////
-// Track element.
-class Track {
- public:
-  // The |seed| parameter is used to synthesize a UID for the track.
-  explicit Track(unsigned int* seed);
-  virtual ~Track();
-
-  // Adds a ContentEncoding element to the Track. Returns true on success.
-  virtual bool AddContentEncoding();
-
-  // Returns the ContentEncoding by index. Returns NULL if there is no
-  // ContentEncoding match.
-  ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
-
-  // Returns the size in bytes for the payload of the Track element.
-  virtual uint64 PayloadSize() const;
-
-  // Returns the size in bytes of the Track element.
-  virtual uint64 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);
-
-  void set_codec_id(const char* codec_id);
-  const char* codec_id() const { return codec_id_; }
-  const uint8* 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) {
-    max_block_additional_id_ = max_block_additional_id;
-  }
-  uint64 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) {
-    seek_pre_roll_ = seek_pre_roll;
-  }
-  uint64 seek_pre_roll() const { return seek_pre_roll_; }
-  void set_default_duration(uint64 default_duration) {
-    default_duration_ = default_duration;
-  }
-  uint64 default_duration() const { return default_duration_; }
-
-  uint64 codec_private_length() const { return codec_private_length_; }
-  uint32 content_encoding_entries_size() const {
-    return content_encoding_entries_size_;
-  }
-
- private:
-  // Track element names.
-  char* codec_id_;
-  uint8* codec_private_;
-  char* language_;
-  uint64 max_block_additional_id_;
-  char* name_;
-  uint64 number_;
-  uint64 type_;
-  uint64 uid_;
-  uint64 codec_delay_;
-  uint64 seek_pre_roll_;
-  uint64 default_duration_;
-
-  // Size of the CodecPrivate data in bytes.
-  uint64 codec_private_length_;
-
-  // ContentEncoding element list.
-  ContentEncoding** content_encoding_entries_;
-
-  // Number of ContentEncoding elements added.
-  uint32 content_encoding_entries_size_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
-};
-
-///////////////////////////////////////////////////////////////
-// Track that has video specific elements.
-class VideoTrack : public Track {
- public:
-  // Supported modes for stereo 3D.
-  enum StereoMode {
-    kMono = 0,
-    kSideBySideLeftIsFirst = 1,
-    kTopBottomRightIsFirst = 2,
-    kTopBottomLeftIsFirst = 3,
-    kSideBySideRightIsFirst = 11
-  };
-
-  enum AlphaMode { kNoAlpha = 0, kAlpha = 1 };
-
-  // The |seed| parameter is used to synthesize a UID for the track.
-  explicit VideoTrack(unsigned int* seed);
-  virtual ~VideoTrack();
-
-  // Returns the size in bytes for the payload of the Track element plus the
-  // video specific elements.
-  virtual uint64 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);
-
-  // Sets the video's alpha mode. Returns true on success.
-  bool SetAlphaMode(uint64 alpha_mode);
-
-  void set_display_height(uint64 height) { display_height_ = height; }
-  uint64 display_height() const { return display_height_; }
-  void set_display_width(uint64 width) { display_width_ = width; }
-  uint64 display_width() const { return display_width_; }
-
-  void set_crop_left(uint64 crop_left) { crop_left_ = crop_left; }
-  uint64 crop_left() const { return crop_left_; }
-  void set_crop_right(uint64 crop_right) { crop_right_ = crop_right; }
-  uint64 crop_right() const { return crop_right_; }
-  void set_crop_top(uint64 crop_top) { crop_top_ = crop_top; }
-  uint64 crop_top() const { return crop_top_; }
-  void set_crop_bottom(uint64 crop_bottom) { crop_bottom_ = crop_bottom; }
-  uint64 crop_bottom() const { return crop_bottom_; }
-
-  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_; }
-
- private:
-  // Returns the size in bytes of the Video element.
-  uint64 VideoPayloadSize() const;
-
-  // Video track element names.
-  uint64 display_height_;
-  uint64 display_width_;
-  uint64 crop_left_;
-  uint64 crop_right_;
-  uint64 crop_top_;
-  uint64 crop_bottom_;
-  double frame_rate_;
-  uint64 height_;
-  uint64 stereo_mode_;
-  uint64 alpha_mode_;
-  uint64 width_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
-};
-
-///////////////////////////////////////////////////////////////
-// Track that has audio specific elements.
-class AudioTrack : public Track {
- public:
-  // The |seed| parameter is used to synthesize a UID for the track.
-  explicit AudioTrack(unsigned int* seed);
-  virtual ~AudioTrack();
-
-  // Returns the size in bytes for the payload of the Track element plus the
-  // audio specific elements.
-  virtual uint64 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_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_;
-  double sample_rate_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
-};
-
-///////////////////////////////////////////////////////////////
-// Tracks element
-class Tracks {
- public:
-  // Audio and video type defined by the Matroska specs.
-  enum { kVideo = 0x1, kAudio = 0x2 };
-
-  static const char kOpusCodecId[];
-  static const char kVorbisCodecId[];
-  static const char kVp8CodecId[];
-  static const char kVp9CodecId[];
-  static const char kVp10CodecId[];
-
-  Tracks();
-  ~Tracks();
-
-  // Adds a Track element to the Tracks object. |track| will be owned and
-  // 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);
-
-  // Returns the track by index. Returns NULL if there is no track match.
-  const Track* GetTrackByIndex(uint32 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;
-
-  // Returns true if the track number is an audio track.
-  bool TrackIsAudio(uint64 track_number) const;
-
-  // Returns true if the track number is a video track.
-  bool TrackIsVideo(uint64 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_; }
-
- private:
-  // Track element list.
-  Track** track_entries_;
-
-  // Number of Track elements added.
-  uint32 track_entries_size_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tracks);
-};
-
-///////////////////////////////////////////////////////////////
-// Chapter element
-//
-class Chapter {
- public:
-  // Set the identifier for this chapter.  (This corresponds to the
-  // Cue Identifier line in WebVTT.)
-  // TODO(matthewjheaney): the actual serialization of this item in
-  // MKV is pending.
-  bool set_id(const char* id);
-
-  // 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);
-
-  // Sets the uid for this chapter. Primarily used to enable
-  // deterministic output from the muxer.
-  void set_uid(const uint64 uid) { uid_ = uid; }
-
-  // Add a title string to this chapter, per the semantics described
-  // here:
-  //  http://www.matroska.org/technical/specs/index.html
-  //
-  // The title ("chapter string") is a UTF-8 string.
-  //
-  // The language has ISO 639-2 representation, described here:
-  //  http://www.loc.gov/standards/iso639-2/englangn.html
-  //  http://www.loc.gov/standards/iso639-2/php/English_list.php
-  // If you specify NULL as the language value, this implies
-  // English ("eng").
-  //
-  // The country value corresponds to the codes listed here:
-  //  http://www.iana.org/domains/root/db/
-  //
-  // The function returns false if the string could not be allocated.
-  bool add_string(const char* title, const char* language, const char* country);
-
- private:
-  friend class Chapters;
-
-  // For storage of chapter titles that differ by language.
-  class Display {
-   public:
-    // Establish representation invariant for new Display object.
-    void Init();
-
-    // Reclaim resources, in anticipation of destruction.
-    void Clear();
-
-    // Copies the title to the |title_| member.  Returns false on
-    // error.
-    bool set_title(const char* title);
-
-    // Copies the language to the |language_| member.  Returns false
-    // on error.
-    bool set_language(const char* language);
-
-    // Copies the country to the |country_| member.  Returns false on
-    // error.
-    bool set_country(const char* country);
-
-    // 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;
-
-   private:
-    char* title_;
-    char* language_;
-    char* country_;
-  };
-
-  Chapter();
-  ~Chapter();
-
-  // Establish the representation invariant for a newly-created
-  // Chapter object.  The |seed| parameter is used to create the UID
-  // for this chapter atom.
-  void Init(unsigned int* seed);
-
-  // Copies this Chapter object to a different one.  This is used when
-  // expanding a plain array of Chapter objects (see Chapters).
-  void ShallowCopy(Chapter* dst) const;
-
-  // Reclaim resources used by this Chapter object, pending its
-  // destruction.
-  void Clear();
-
-  // If there is no storage remaining on the |displays_| array for a
-  // new display object, creates a new, longer array and copies the
-  // existing Display objects to the new array.  Returns false if the
-  // array cannot be expanded.
-  bool ExpandDisplaysArray();
-
-  // 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;
-
-  // The string identifier for this chapter (corresponds to WebVTT cue
-  // identifier).
-  char* id_;
-
-  // Start timecode of the chapter.
-  uint64 start_timecode_;
-
-  // Stop timecode of the chapter.
-  uint64 end_timecode_;
-
-  // The binary identifier for this chapter.
-  uint64 uid_;
-
-  // The Atom element can contain multiple Display sub-elements, as
-  // the same logical title can be rendered in different languages.
-  Display* displays_;
-
-  // The physical length (total size) of the |displays_| array.
-  int displays_size_;
-
-  // The logical length (number of active elements) on the |displays_|
-  // array.
-  int displays_count_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapter);
-};
-
-///////////////////////////////////////////////////////////////
-// Chapters element
-//
-class Chapters {
- public:
-  Chapters();
-  ~Chapters();
-
-  Chapter* AddChapter(unsigned int* seed);
-
-  // Returns the number of chapters that have been added.
-  int Count() const;
-
-  // Output the Chapters element to the writer. Returns true on success.
-  bool Write(IMkvWriter* writer) const;
-
- private:
-  // Expands the chapters_ array if there is not enough space to contain
-  // another chapter object.  Returns true on success.
-  bool ExpandChaptersArray();
-
-  // 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;
-
-  // Total length of the chapters_ array.
-  int chapters_size_;
-
-  // Number of active chapters on the chapters_ array.
-  int chapters_count_;
-
-  // Array for storage of chapter objects.
-  Chapter* chapters_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapters);
-};
-
-///////////////////////////////////////////////////////////////
-// Tag element
-//
-class Tag {
- public:
-  bool add_simple_tag(const char* tag_name, const char* tag_string);
-
- private:
-  // Tags calls Clear and the destructor of Tag
-  friend class Tags;
-
-  // For storage of simple tags
-  class SimpleTag {
-   public:
-    // Establish representation invariant for new SimpleTag object.
-    void Init();
-
-    // Reclaim resources, in anticipation of destruction.
-    void Clear();
-
-    // Copies the title to the |tag_name_| member.  Returns false on
-    // error.
-    bool set_tag_name(const char* tag_name);
-
-    // Copies the language to the |tag_string_| member.  Returns false
-    // on error.
-    bool set_tag_string(const char* tag_string);
-
-    // 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;
-
-   private:
-    char* tag_name_;
-    char* tag_string_;
-  };
-
-  Tag();
-  ~Tag();
-
-  // Copies this Tag object to a different one.  This is used when
-  // expanding a plain array of Tag objects (see Tags).
-  void ShallowCopy(Tag* dst) const;
-
-  // Reclaim resources used by this Tag object, pending its
-  // destruction.
-  void Clear();
-
-  // If there is no storage remaining on the |simple_tags_| array for a
-  // new display object, creates a new, longer array and copies the
-  // existing SimpleTag objects to the new array.  Returns false if the
-  // array cannot be expanded.
-  bool ExpandSimpleTagsArray();
-
-  // 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;
-
-  // The Atom element can contain multiple SimpleTag sub-elements
-  SimpleTag* simple_tags_;
-
-  // The physical length (total size) of the |simple_tags_| array.
-  int simple_tags_size_;
-
-  // The logical length (number of active elements) on the |simple_tags_|
-  // array.
-  int simple_tags_count_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tag);
-};
-
-///////////////////////////////////////////////////////////////
-// Tags element
-//
-class Tags {
- public:
-  Tags();
-  ~Tags();
-
-  Tag* AddTag();
-
-  // Returns the number of tags that have been added.
-  int Count() const;
-
-  // Output the Tags element to the writer. Returns true on success.
-  bool Write(IMkvWriter* writer) const;
-
- private:
-  // Expands the tags_ array if there is not enough space to contain
-  // another tag object.  Returns true on success.
-  bool ExpandTagsArray();
-
-  // Total length of the tags_ array.
-  int tags_size_;
-
-  // Number of active tags on the tags_ array.
-  int tags_count_;
-
-  // Array for storage of tag objects.
-  Tag* tags_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tags);
-};
-
-///////////////////////////////////////////////////////////////
-// Cluster element
-//
-// Notes:
-//  |Init| must be called before any other method in this class.
-class Cluster {
- public:
-  // |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();
-
-  bool Init(IMkvWriter* ptr_writer);
-
-  // Adds a frame to be output in the file. The frame is written out through
-  // |writer_| if successful. Returns true on success.
-  bool AddFrame(const Frame* frame);
-
-  // Adds a frame to be output in the file. The frame is written out through
-  // |writer_| if successful. Returns true on success.
-  // Inputs:
-  //   data: Pointer to the data
-  //   length: Length of the data
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.  The range of allowed values is [1, 126].
-  //   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 is_key);
-
-  // Adds a frame to be output in the file. The frame is written out through
-  // |writer_| if successful. Returns true on success.
-  // Inputs:
-  //   data: Pointer to the data
-  //   length: Length of the data
-  //   additional: Pointer to the additional data
-  //   additional_length: Length of the additional data
-  //   add_id: Value of BlockAddID element
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.  The range of allowed values is [1, 126].
-  //   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);
-
-  // Adds a frame to be output in the file. The frame is written out through
-  // |writer_| if successful. Returns true on success.
-  // Inputs:
-  //   data: Pointer to the data.
-  //   length: Length of the data.
-  //   discard_padding: DiscardPadding element value.
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.  The range of allowed values is [1, 126].
-  //   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);
-
-  // Writes a frame of metadata to the output medium; returns true on
-  // success.
-  // Inputs:
-  //   data: Pointer to the data
-  //   length: Length of the data
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.  The range of allowed values is [1, 126].
-  //   timecode:     Absolute (not relative to cluster) timestamp of the
-  //                 metadata frame, expressed in timecode units.
-  //   duration:     Duration of metadata frame, in timecode units.
-  //
-  // 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);
-
-  // Increments the size of the cluster's data in bytes.
-  void AddPayloadSize(uint64 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.
-  bool Finalize();
-
-  // Returns the size in bytes for the entire Cluster element.
-  uint64 Size() const;
-
-  // Given |abs_timecode|, calculates timecode relative to most recent timecode.
-  // Returns -1 on failure, or a relative timecode.
-  int64 GetRelativeTimecode(int64 abs_timecode) const;
-
-  int64 size_position() const { return size_position_; }
-  int32 blocks_added() const { return blocks_added_; }
-  uint64 payload_size() const { return payload_size_; }
-  int64 position_for_cues() const { return position_for_cues_; }
-  uint64 timecode() const { return timecode_; }
-  uint64 timecode_scale() const { return timecode_scale_; }
-
- private:
-  // 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.
-  bool PreWriteBlock();
-
-  // Utility method used by the |DoWriteFrame*| methods that handles the book
-  // keeping required after each block is written.
-  void PostWriteBlock(uint64 element_size);
-
-  // Does some verification and calls WriteFrame.
-  bool DoWriteFrame(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_;
-
-  // Flag telling if the cluster has been closed.
-  bool finalized_;
-
-  // Flag telling if the cluster's header has been written.
-  bool header_written_;
-
-  // The size of the cluster elements in bytes.
-  uint64 payload_size_;
-
-  // The file position used for cue points.
-  const int64 position_for_cues_;
-
-  // The file position of the cluster's size element.
-  int64 size_position_;
-
-  // The absolute timecode of the cluster.
-  const uint64 timecode_;
-
-  // The timecode scale of the Segment containing the cluster.
-  const uint64 timecode_scale_;
-
-  // Pointer to the writer object. Not owned by this class.
-  IMkvWriter* writer_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cluster);
-};
-
-///////////////////////////////////////////////////////////////
-// SeekHead element
-class SeekHead {
- public:
-  SeekHead();
-  ~SeekHead();
-
-  // TODO(fgalligan): Change this to reserve a certain size. Then check how
-  // big the seek entry to be added is as not every seek entry will be the
-  // maximum size it could be.
-  // 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);
-
-  // 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;
-
-  // Returns the position of the Seek Entry at the given index. Returns -1 if
-  // index is out of range.
-  uint64 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);
-
-  // 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;
-
- private:
-  // Returns the maximum size in bytes of one seek entry.
-  uint64 MaxEntrySize() const;
-
-  // Seek entry id element list.
-  uint32 seek_entry_id_[kSeekEntryCount];
-
-  // Seek entry pos element list.
-  uint64 seek_entry_pos_[kSeekEntryCount];
-
-  // The file position of SeekHead element.
-  int64 start_pos_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
-};
-
-///////////////////////////////////////////////////////////////
-// Segment Information element
-class SegmentInfo {
- public:
-  SegmentInfo();
-  ~SegmentInfo();
-
-  // Will update the duration if |duration_| is > 0.0. Returns true on success.
-  bool Finalize(IMkvWriter* writer) const;
-
-  // Sets |muxing_app_| and |writing_app_|.
-  bool Init();
-
-  // Output the Segment Information element to the writer. Returns true on
-  // success.
-  bool Write(IMkvWriter* writer);
-
-  void set_duration(double duration) { duration_ = duration; }
-  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_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_; }
-
- private:
-  // Segment Information element names.
-  // Initially set to -1 to signify that a duration has not been set and should
-  // not be written out.
-  double duration_;
-  // Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
-  char* muxing_app_;
-  uint64 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_;
-
-  // The file position of the duration element.
-  int64 duration_pos_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
-};
-
-///////////////////////////////////////////////////////////////
-// This class represents the main segment in a WebM file. Currently only
-// supports one Segment element.
-//
-// Notes:
-//  |Init| must be called before any other method in this class.
-class Segment {
- public:
-  enum Mode { kLive = 0x1, kFile = 0x2 };
-
-  enum CuesPosition {
-    kAfterClusters = 0x0,  // Position Cues after Clusters - Default
-    kBeforeClusters = 0x1  // Position Cues before Clusters
-  };
-
-  const static uint32 kDefaultDocTypeVersion = 2;
-  const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
-
-  Segment();
-  ~Segment();
-
-  // Initializes |SegmentInfo| and returns result. Always returns false when
-  // |ptr_writer| is NULL.
-  bool Init(IMkvWriter* ptr_writer);
-
-  // Adds a generic track to the segment.  Returns the newly-allocated
-  // track object (which is owned by the segment) on success, NULL on
-  // 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);
-
-  // 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);
-
-  // Adds an empty chapter to the chapters of this segment.  Returns
-  // non-NULL on success.  After adding the chapter, the caller should
-  // populate its fields via the Chapter member functions.
-  Chapter* AddChapter();
-
-  // Adds an empty tag to the tags of this segment.  Returns
-  // non-NULL on success.  After adding the tag, the caller should
-  // populate its fields via the Tag member functions.
-  Tag* AddTag();
-
-  // Adds a cue point to the Cues element. |timestamp| is the time in
-  // 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);
-
-  // Adds a frame to be output in the file. Returns true on success.
-  // Inputs:
-  //   data: Pointer to the data
-  //   length: Length of the data
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 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);
-
-  // Writes a frame of metadata to the output medium; returns true on
-  // success.
-  // Inputs:
-  //   data: Pointer to the data
-  //   length: Length of the data
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.
-  //   timecode:     Absolute timestamp of the metadata frame, expressed
-  //                 in nanosecond units.
-  //   duration:     Duration of metadata frame, in nanosecond units.
-  //
-  // 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);
-
-  // Writes a frame with additional data to the output medium; returns true on
-  // success.
-  // Inputs:
-  //   data: Pointer to the data.
-  //   length: Length of the data.
-  //   additional: Pointer to additional data.
-  //   additional_length: Length of additional data.
-  //   add_id: Additional ID which identifies the type of additional data.
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.
-  //   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);
-
-  // Writes a frame with DiscardPadding to the output medium; returns true on
-  // success.
-  // Inputs:
-  //   data: Pointer to the data.
-  //   length: Length of the data.
-  //   discard_padding: DiscardPadding element value.
-  //   track_number: Track to add the data to. Value returned by Add track
-  //                 functions.
-  //   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);
-
-  // Writes a Frame to the output medium. Chooses the correct way of writing
-  // the frame (Block vs SimpleBlock) based on the parameters passed.
-  // Inputs:
-  //   frame: frame object
-  bool AddGenericFrame(const Frame* frame);
-
-  // Adds a VP8 video track to the segment. Returns the number of the track on
-  // 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);
-
-  // 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
-  // writer is not seekable of if chunking is set to true.
-  // Input parameters:
-  // reader - an IMkvReader object created with the same underlying file of the
-  //          current writer object. Make sure to close the existing writer
-  //          object before creating this so that all the data is properly
-  //          flushed and available for reading.
-  // writer - an IMkvWriter object pointing to a *different* file than the one
-  //          pointed by the current writer object. This file will contain the
-  //          Cues element before the Clusters.
-  bool CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
-                                     IMkvWriter* writer);
-
-  // 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);
-
-  // This will force the muxer to create a new Cluster when the next frame is
-  // added.
-  void ForceNewClusterOnNextFrame();
-
-  // Writes out any frames that have not been written out. Finalizes the last
-  // cluster. May update the size and duration of the segment. May output the
-  // Cues element. May finalize the SeekHead element. Returns true on success.
-  bool Finalize();
-
-  // Returns the Cues object.
-  Cues* GetCues() { return &cues_; }
-
-  // Returns the Segment Information object.
-  const SegmentInfo* GetSegmentInfo() const { return &segment_info_; }
-  SegmentInfo* GetSegmentInfo() { return &segment_info_; }
-
-  // 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;
-
-  // Toggles whether to output a cues element.
-  void OutputCues(bool output_cues);
-
-  // 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
-  // |filename|.hdr and the data chunks will be named
-  // |filename|_XXXXXX.chk. Chunking implies that the muxer will be writing
-  // to files so the muxer will use the default MkvWriter class to control
-  // what data is written to what files. Returns true on success.
-  // TODO: Should we change the IMkvWriter Interface to add Open and Close?
-  // That will force the interface to be dependent on files.
-  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) {
-    max_cluster_duration_ = max_cluster_duration;
-  }
-  uint64 max_cluster_duration() const { return max_cluster_duration_; }
-  void set_max_cluster_size(uint64 max_cluster_size) {
-    max_cluster_size_ = max_cluster_size;
-  }
-  uint64 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_; }
-  bool output_cues() const { return output_cues_; }
-  const SegmentInfo* segment_info() const { return &segment_info_; }
-
- private:
-  // Checks if header information has been output and initialized. If not it
-  // will output the Segment element and initialize the SeekHead elment and
-  // Cues elements.
-  bool CheckHeaderInfo();
-
-  // Sets |doc_type_version_| based on the current element requirements.
-  void UpdateDocTypeVersion();
-
-  // Sets |name| according to how many chunks have been written. |ext| is the
-  // file extension. |name| must be deleted by the calling app. Returns true
-  // on success.
-  bool UpdateChunkName(const char* ext, char** name) const;
-
-  // 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();
-
-  // Adds the frame to our frame array.
-  bool QueueFrame(Frame* frame);
-
-  // Output all frames that are queued. Returns -1 on error, otherwise
-  // it returns the number of frames written.
-  int WriteFramesAll();
-
-  // 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);
-
-  // Outputs the segment header, Segment Information element, SeekHead element,
-  // and Tracks element to |writer_|.
-  bool WriteSegmentHeader();
-
-  // Given a frame with the specified timestamp (nanosecond units) and
-  // keyframe status, determine whether a new cluster should be
-  // created, before writing enqueued frames and the frame itself. The
-  // function returns one of the following values:
-  //  -1 = error: an out-of-order frame was detected
-  //  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;
-
-  // 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);
-
-  // 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);
-
-  // Adjusts Cue Point values (to place Cues before Clusters) so that they
-  // reflect the correct offsets.
-  void MoveCuesBeforeClusters();
-
-  // This function recursively computes the correct cluster offsets (this is
-  // done to move the Cues before Clusters). It recursively updates the change
-  // in size (which indicates a change in cluster offset) until no sizes change.
-  // Parameters:
-  // diff - indicates the difference in size of the Cues element that needs to
-  //        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);
-
-  // Seeds the random number generator used to make UIDs.
-  unsigned int seed_;
-
-  // WebM elements
-  Cues cues_;
-  SeekHead seek_head_;
-  SegmentInfo segment_info_;
-  Tracks tracks_;
-  Chapters chapters_;
-  Tags tags_;
-
-  // Number of chunks written.
-  int chunk_count_;
-
-  // Current chunk filename.
-  char* chunk_name_;
-
-  // Default MkvWriter object created by this class used for writing clusters
-  // out in separate files.
-  MkvWriter* chunk_writer_cluster_;
-
-  // Default MkvWriter object created by this class used for writing Cues
-  // element out to a file.
-  MkvWriter* chunk_writer_cues_;
-
-  // Default MkvWriter object created by this class used for writing the
-  // Matroska header out to a file.
-  MkvWriter* chunk_writer_header_;
-
-  // Flag telling whether or not the muxer is chunking output to multiple
-  // files.
-  bool chunking_;
-
-  // Base filename for the chunked files.
-  char* chunking_base_name_;
-
-  // File position offset where the Clusters end.
-  int64 cluster_end_offset_;
-
-  // List of clusters.
-  Cluster** cluster_list_;
-
-  // Number of cluster pointers allocated in the cluster list.
-  int32 cluster_list_capacity_;
-
-  // Number of clusters in the cluster list.
-  int32 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_;
-
-  // Tells the muxer to force a new cluster on the next Block.
-  bool force_new_cluster_;
-
-  // List of stored audio frames. These variables are used to store frames so
-  // the muxer can follow the guideline "Audio blocks that contain the video
-  // key frame's timecode should be in the same cluster as the video key frame
-  // block."
-  Frame** frames_;
-
-  // Number of frame pointers allocated in the frame list.
-  int32 frames_capacity_;
-
-  // Number of frames in the frame list.
-  int32 frames_size_;
-
-  // Flag telling if a video track has been added to the segment.
-  bool has_video_;
-
-  // Flag telling if the segment's header has been written.
-  bool header_written_;
-
-  // Duration of the last block in nanoseconds.
-  uint64 last_block_duration_;
-
-  // Last timestamp in nanoseconds added to a cluster.
-  uint64 last_timestamp_;
-
-  // Last timestamp in nanoseconds by track number added to a cluster.
-  uint64 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_;
-
-  // 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_;
-
-  // The mode that segment is in. If set to |kLive| the writer must not
-  // seek backwards.
-  Mode mode_;
-
-  // Flag telling the muxer that a new cue point should be added.
-  bool new_cuepoint_;
-
-  // TODO(fgalligan): Should we add support for more than one Cues element?
-  // Flag whether or not the muxer should output a Cues element.
-  bool output_cues_;
-
-  // The size of the EBML header, used to validate the header if
-  // WriteEbmlHeader() is called more than once.
-  int32 ebml_header_size_;
-
-  // The file position of the segment's payload.
-  int64 payload_pos_;
-
-  // The file position of the element's size.
-  int64 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_;
-
-  // Pointer to the writer objects. Not owned by this class.
-  IMkvWriter* writer_cluster_;
-  IMkvWriter* writer_cues_;
-  IMkvWriter* writer_header_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
-};
-
-}  // end namespace mkvmuxer
-
-#endif  // MKVMUXER_HPP
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.cc
@@ -1,0 +1,3759 @@
+// 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)
+    : 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),
+      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()))
+    return false;
+  AddPayloadSize(EbmlElementSize(libwebm::kMkvTimecode, timecode()));
+  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),
+      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;
+}
+
+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_);
+  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
\ No newline at end of file
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxer.h
@@ -1,0 +1,1684 @@
+// 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_MKVMUXER_H_
+#define MKVMUXER_MKVMUXER_H_
+
+#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;
+}  // namespace mkvparser
+
+namespace mkvmuxer {
+
+class MkvWriter;
+class Segment;
+
+const uint64_t kMaxTrackNumber = 126;
+
+///////////////////////////////////////////////////////////////
+// Interface used by the mkvmuxer to write out the Mkv data.
+class IMkvWriter {
+ public:
+  // Writes out |len| bytes of |buf|. Returns 0 on success.
+  virtual int32_t Write(const void* buf, uint32_t len) = 0;
+
+  // Returns the offset of the output position from the beginning of the
+  // output.
+  virtual int64_t Position() const = 0;
+
+  // Set the current File position. Returns 0 on success.
+  virtual int32_t Position(int64_t position) = 0;
+
+  // Returns true if the writer is seekable.
+  virtual bool Seekable() const = 0;
+
+  // Element start notification. Called whenever an element identifier is about
+  // to be written to the stream. |element_id| is the element identifier, and
+  // |position| is the location in the WebM stream where the first octet of the
+  // element identifier will be written.
+  // Note: the |MkvId| enumeration in webmids.hpp defines element values.
+  virtual void ElementStartNotify(uint64_t element_id, int64_t position) = 0;
+
+ protected:
+  IMkvWriter();
+  virtual ~IMkvWriter();
+
+ private:
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter);
+};
+
+// Writes out the EBML header for a WebM file. This function must be called
+// before any other libwebm writing functions are called.
+bool WriteEbmlHeader(IMkvWriter* writer, uint64_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_t start,
+                 int64_t size);
+
+///////////////////////////////////////////////////////////////
+// Class to hold data the will be written to a block.
+class Frame {
+ public:
+  Frame();
+  ~Frame();
+
+  // Sets this frame's contents based on |frame|. Returns true on success. On
+  // failure, this frame's existing contents may be lost.
+  bool CopyFrom(const Frame& frame);
+
+  // Copies |frame| data into |frame_|. Returns true on success.
+  bool Init(const uint8_t* frame, uint64_t length);
+
+  // Copies |additional| data into |additional_|. Returns true on success.
+  bool AddAdditionalData(const uint8_t* additional, uint64_t length,
+                         uint64_t add_id);
+
+  // Returns true if the frame has valid parameters.
+  bool IsValid() const;
+
+  // Returns true if the frame can be written as a SimpleBlock based on current
+  // parameters.
+  bool CanBeSimpleBlock() const;
+
+  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_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_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_t add_id_;
+
+  // Pointer to additional data. Owned by this class.
+  uint8_t* additional_;
+
+  // Length of the additional data.
+  uint64_t additional_length_;
+
+  // Duration of the frame in nanoseconds.
+  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_t* frame_;
+
+  // Flag telling if the data should set the key flag of a block.
+  bool is_key_;
+
+  // Length of the data.
+  uint64_t length_;
+
+  // Mkv track number the data is associated with.
+  uint64_t track_number_;
+
+  // Timestamp of the data in nanoseconds.
+  uint64_t timestamp_;
+
+  // Discard padding for the frame.
+  int64_t discard_padding_;
+
+  // Reference block timestamp.
+  int64_t reference_block_timestamp_;
+
+  // Flag indicating if |reference_block_timestamp_| has been set.
+  bool reference_block_timestamp_set_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Frame);
+};
+
+///////////////////////////////////////////////////////////////
+// Class to hold one cue point in a Cues element.
+class CuePoint {
+ public:
+  CuePoint();
+  ~CuePoint();
+
+  // Returns the size in bytes for the entire CuePoint element.
+  uint64_t Size() const;
+
+  // Output the CuePoint element to the writer. Returns true on success.
+  bool Write(IMkvWriter* writer) const;
+
+  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;
+  }
+  bool output_block_number() const { return output_block_number_; }
+
+ private:
+  // Returns the size in bytes for the payload of the CuePoint element.
+  uint64_t PayloadSize() const;
+
+  // Absolute timecode according to the segment time base.
+  uint64_t time_;
+
+  // The Track element associated with the CuePoint.
+  uint64_t track_;
+
+  // The position of the Cluster containing the Block.
+  uint64_t cluster_pos_;
+
+  // Number of the Block within the Cluster, starting from 1.
+  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.
+  bool output_block_number_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(CuePoint);
+};
+
+///////////////////////////////////////////////////////////////
+// Cues element.
+class Cues {
+ public:
+  Cues();
+  ~Cues();
+
+  // Adds a cue point to the Cues element. Returns true on success.
+  bool AddCue(CuePoint* cue);
+
+  // Returns the cue point by index. Returns NULL if there is no cue point
+  // match.
+  CuePoint* GetCueByIndex(int32_t index) const;
+
+  // Returns the total size of the Cues element
+  uint64_t Size();
+
+  // Output the Cues element to the writer. Returns true on success.
+  bool Write(IMkvWriter* writer) const;
+
+  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;
+  }
+  bool output_block_number() const { return output_block_number_; }
+
+ private:
+  // Number of allocated elements in |cue_entries_|.
+  int32_t cue_entries_capacity_;
+
+  // Number of CuePoints in |cue_entries_|.
+  int32_t cue_entries_size_;
+
+  // CuePoint list.
+  CuePoint** cue_entries_;
+
+  // 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.
+  bool output_block_number_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues);
+};
+
+///////////////////////////////////////////////////////////////
+// ContentEncAESSettings element
+class ContentEncAESSettings {
+ public:
+  enum { kCTR = 1 };
+
+  ContentEncAESSettings();
+  ~ContentEncAESSettings() {}
+
+  // Returns the size in bytes for the ContentEncAESSettings element.
+  uint64_t Size() const;
+
+  // Writes out the ContentEncAESSettings element to |writer|. Returns true on
+  // success.
+  bool Write(IMkvWriter* writer) const;
+
+  uint64_t cipher_mode() const { return cipher_mode_; }
+
+ private:
+  // Returns the size in bytes for the payload of the ContentEncAESSettings
+  // element.
+  uint64_t PayloadSize() const;
+
+  // Sub elements
+  uint64_t cipher_mode_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
+};
+
+///////////////////////////////////////////////////////////////
+// ContentEncoding element
+// Elements used to describe if the track data has been encrypted or
+// compressed with zlib or header stripping.
+// Currently only whole frames can be encrypted with AES. This dictates that
+// ContentEncodingOrder will be 0, ContentEncodingScope will be 1,
+// ContentEncodingType will be 1, and ContentEncAlgo will be 5.
+class ContentEncoding {
+ public:
+  ContentEncoding();
+  ~ContentEncoding();
+
+  // Sets the content encryption id. Copies |length| bytes from |id| to
+  // |enc_key_id_|. Returns true on success.
+  bool SetEncryptionID(const uint8_t* id, uint64_t length);
+
+  // Returns the size in bytes for the ContentEncoding element.
+  uint64_t Size() const;
+
+  // Writes out the ContentEncoding element to |writer|. Returns true on
+  // success.
+  bool Write(IMkvWriter* writer) const;
+
+  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_t EncodingSize(uint64_t compresion_size,
+                        uint64_t encryption_size) const;
+
+  // Returns the size in bytes for the encryption elements.
+  uint64_t EncryptionSize() const;
+
+  // Track element names
+  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_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:
+  // The |seed| parameter is used to synthesize a UID for the track.
+  explicit Track(unsigned int* seed);
+  virtual ~Track();
+
+  // Adds a ContentEncoding element to the Track. Returns true on success.
+  virtual bool AddContentEncoding();
+
+  // Returns the ContentEncoding by index. Returns NULL if there is no
+  // ContentEncoding match.
+  ContentEncoding* GetContentEncodingByIndex(uint32_t index) const;
+
+  // Returns the size in bytes for the payload of the Track element.
+  virtual uint64_t PayloadSize() const;
+
+  // Returns the size in bytes of the Track element.
+  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_t* codec_private, uint64_t length);
+
+  void set_codec_id(const char* codec_id);
+  const char* codec_id() const { return codec_id_; }
+  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_t max_block_additional_id) {
+    max_block_additional_id_ = 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_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_t seek_pre_roll() const { return seek_pre_roll_; }
+  void set_default_duration(uint64_t default_duration) {
+    default_duration_ = default_duration;
+  }
+  uint64_t default_duration() const { return default_duration_; }
+
+  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_t* codec_private_;
+  char* language_;
+  uint64_t max_block_additional_id_;
+  char* name_;
+  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_t codec_private_length_;
+
+  // ContentEncoding element list.
+  ContentEncoding** content_encoding_entries_;
+
+  // Number of ContentEncoding elements added.
+  uint32_t content_encoding_entries_size_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
+};
+
+///////////////////////////////////////////////////////////////
+// Track that has video specific elements.
+class VideoTrack : public Track {
+ public:
+  // Supported modes for stereo 3D.
+  enum StereoMode {
+    kMono = 0,
+    kSideBySideLeftIsFirst = 1,
+    kTopBottomRightIsFirst = 2,
+    kTopBottomLeftIsFirst = 3,
+    kSideBySideRightIsFirst = 11
+  };
+
+  enum AlphaMode { kNoAlpha = 0, kAlpha = 1 };
+
+  // The |seed| parameter is used to synthesize a UID for the track.
+  explicit VideoTrack(unsigned int* seed);
+  virtual ~VideoTrack();
+
+  // Returns the size in bytes for the payload of the Track element plus the
+  // video specific elements.
+  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_t stereo_mode);
+
+  // Sets the video's alpha mode. Returns true on success.
+  bool SetAlphaMode(uint64_t alpha_mode);
+
+  void set_display_height(uint64_t height) { display_height_ = height; }
+  uint64_t display_height() const { return display_height_; }
+  void set_display_width(uint64_t width) { display_width_ = width; }
+  uint64_t display_width() const { return display_width_; }
+
+  void set_crop_left(uint64_t crop_left) { crop_left_ = crop_left; }
+  uint64_t crop_left() const { return crop_left_; }
+  void set_crop_right(uint64_t crop_right) { crop_right_ = crop_right; }
+  uint64_t crop_right() const { return crop_right_; }
+  void set_crop_top(uint64_t crop_top) { crop_top_ = crop_top; }
+  uint64_t crop_top() const { return crop_top_; }
+  void set_crop_bottom(uint64_t crop_bottom) { crop_bottom_ = crop_bottom; }
+  uint64_t crop_bottom() const { return crop_bottom_; }
+
+  void set_frame_rate(double frame_rate) { frame_rate_ = frame_rate; }
+  double frame_rate() const { return frame_rate_; }
+  void set_height(uint64_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_t VideoPayloadSize() const;
+
+  // Video track element names.
+  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_t height_;
+  uint64_t stereo_mode_;
+  uint64_t alpha_mode_;
+  uint64_t width_;
+
+  Colour* colour_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
+};
+
+///////////////////////////////////////////////////////////////
+// Track that has audio specific elements.
+class AudioTrack : public Track {
+ public:
+  // The |seed| parameter is used to synthesize a UID for the track.
+  explicit AudioTrack(unsigned int* seed);
+  virtual ~AudioTrack();
+
+  // Returns the size in bytes for the payload of the Track element plus the
+  // audio specific elements.
+  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_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_t bit_depth_;
+  uint64_t channels_;
+  double sample_rate_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
+};
+
+///////////////////////////////////////////////////////////////
+// Tracks element
+class Tracks {
+ public:
+  // Audio and video type defined by the Matroska specs.
+  enum { kVideo = 0x1, kAudio = 0x2 };
+
+  static const char kOpusCodecId[];
+  static const char kVorbisCodecId[];
+  static const char kVp8CodecId[];
+  static const char kVp9CodecId[];
+  static const char kVp10CodecId[];
+
+  Tracks();
+  ~Tracks();
+
+  // Adds a Track element to the Tracks object. |track| will be owned and
+  // 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_t number);
+
+  // Returns the track by index. Returns NULL if there is no track match.
+  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_t track_number) const;
+
+  // Returns true if the track number is an audio track.
+  bool TrackIsAudio(uint64_t track_number) const;
+
+  // Returns true if the track number is a video track.
+  bool TrackIsVideo(uint64_t track_number) const;
+
+  // Output the Tracks element to the writer. Returns true on success.
+  bool Write(IMkvWriter* writer) const;
+
+  uint32_t track_entries_size() const { return track_entries_size_; }
+
+ private:
+  // Track element list.
+  Track** track_entries_;
+
+  // Number of Track elements added.
+  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);
+};
+
+///////////////////////////////////////////////////////////////
+// Chapter element
+//
+class Chapter {
+ public:
+  // Set the identifier for this chapter.  (This corresponds to the
+  // Cue Identifier line in WebVTT.)
+  // TODO(matthewjheaney): the actual serialization of this item in
+  // MKV is pending.
+  bool set_id(const char* id);
+
+  // 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_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_t uid) { uid_ = uid; }
+
+  // Add a title string to this chapter, per the semantics described
+  // here:
+  //  http://www.matroska.org/technical/specs/index.html
+  //
+  // The title ("chapter string") is a UTF-8 string.
+  //
+  // The language has ISO 639-2 representation, described here:
+  //  http://www.loc.gov/standards/iso639-2/englangn.html
+  //  http://www.loc.gov/standards/iso639-2/php/English_list.php
+  // If you specify NULL as the language value, this implies
+  // English ("eng").
+  //
+  // The country value corresponds to the codes listed here:
+  //  http://www.iana.org/domains/root/db/
+  //
+  // The function returns false if the string could not be allocated.
+  bool add_string(const char* title, const char* language, const char* country);
+
+ private:
+  friend class Chapters;
+
+  // For storage of chapter titles that differ by language.
+  class Display {
+   public:
+    // Establish representation invariant for new Display object.
+    void Init();
+
+    // Reclaim resources, in anticipation of destruction.
+    void Clear();
+
+    // Copies the title to the |title_| member.  Returns false on
+    // error.
+    bool set_title(const char* title);
+
+    // Copies the language to the |language_| member.  Returns false
+    // on error.
+    bool set_language(const char* language);
+
+    // Copies the country to the |country_| member.  Returns false on
+    // error.
+    bool set_country(const char* country);
+
+    // 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_t WriteDisplay(IMkvWriter* writer) const;
+
+   private:
+    char* title_;
+    char* language_;
+    char* country_;
+  };
+
+  Chapter();
+  ~Chapter();
+
+  // Establish the representation invariant for a newly-created
+  // Chapter object.  The |seed| parameter is used to create the UID
+  // for this chapter atom.
+  void Init(unsigned int* seed);
+
+  // Copies this Chapter object to a different one.  This is used when
+  // expanding a plain array of Chapter objects (see Chapters).
+  void ShallowCopy(Chapter* dst) const;
+
+  // Reclaim resources used by this Chapter object, pending its
+  // destruction.
+  void Clear();
+
+  // If there is no storage remaining on the |displays_| array for a
+  // new display object, creates a new, longer array and copies the
+  // existing Display objects to the new array.  Returns false if the
+  // array cannot be expanded.
+  bool ExpandDisplaysArray();
+
+  // 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_t WriteAtom(IMkvWriter* writer) const;
+
+  // The string identifier for this chapter (corresponds to WebVTT cue
+  // identifier).
+  char* id_;
+
+  // Start timecode of the chapter.
+  uint64_t start_timecode_;
+
+  // Stop timecode of the chapter.
+  uint64_t end_timecode_;
+
+  // The binary identifier for this chapter.
+  uint64_t uid_;
+
+  // The Atom element can contain multiple Display sub-elements, as
+  // the same logical title can be rendered in different languages.
+  Display* displays_;
+
+  // The physical length (total size) of the |displays_| array.
+  int displays_size_;
+
+  // The logical length (number of active elements) on the |displays_|
+  // array.
+  int displays_count_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapter);
+};
+
+///////////////////////////////////////////////////////////////
+// Chapters element
+//
+class Chapters {
+ public:
+  Chapters();
+  ~Chapters();
+
+  Chapter* AddChapter(unsigned int* seed);
+
+  // Returns the number of chapters that have been added.
+  int Count() const;
+
+  // Output the Chapters element to the writer. Returns true on success.
+  bool Write(IMkvWriter* writer) const;
+
+ private:
+  // Expands the chapters_ array if there is not enough space to contain
+  // another chapter object.  Returns true on success.
+  bool ExpandChaptersArray();
+
+  // 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_t WriteEdition(IMkvWriter* writer) const;
+
+  // Total length of the chapters_ array.
+  int chapters_size_;
+
+  // Number of active chapters on the chapters_ array.
+  int chapters_count_;
+
+  // Array for storage of chapter objects.
+  Chapter* chapters_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapters);
+};
+
+///////////////////////////////////////////////////////////////
+// Tag element
+//
+class Tag {
+ public:
+  bool add_simple_tag(const char* tag_name, const char* tag_string);
+
+ private:
+  // Tags calls Clear and the destructor of Tag
+  friend class Tags;
+
+  // For storage of simple tags
+  class SimpleTag {
+   public:
+    // Establish representation invariant for new SimpleTag object.
+    void Init();
+
+    // Reclaim resources, in anticipation of destruction.
+    void Clear();
+
+    // Copies the title to the |tag_name_| member.  Returns false on
+    // error.
+    bool set_tag_name(const char* tag_name);
+
+    // Copies the language to the |tag_string_| member.  Returns false
+    // on error.
+    bool set_tag_string(const char* tag_string);
+
+    // 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_t Write(IMkvWriter* writer) const;
+
+   private:
+    char* tag_name_;
+    char* tag_string_;
+  };
+
+  Tag();
+  ~Tag();
+
+  // Copies this Tag object to a different one.  This is used when
+  // expanding a plain array of Tag objects (see Tags).
+  void ShallowCopy(Tag* dst) const;
+
+  // Reclaim resources used by this Tag object, pending its
+  // destruction.
+  void Clear();
+
+  // If there is no storage remaining on the |simple_tags_| array for a
+  // new display object, creates a new, longer array and copies the
+  // existing SimpleTag objects to the new array.  Returns false if the
+  // array cannot be expanded.
+  bool ExpandSimpleTagsArray();
+
+  // 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_t Write(IMkvWriter* writer) const;
+
+  // The Atom element can contain multiple SimpleTag sub-elements
+  SimpleTag* simple_tags_;
+
+  // The physical length (total size) of the |simple_tags_| array.
+  int simple_tags_size_;
+
+  // The logical length (number of active elements) on the |simple_tags_|
+  // array.
+  int simple_tags_count_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tag);
+};
+
+///////////////////////////////////////////////////////////////
+// Tags element
+//
+class Tags {
+ public:
+  Tags();
+  ~Tags();
+
+  Tag* AddTag();
+
+  // Returns the number of tags that have been added.
+  int Count() const;
+
+  // Output the Tags element to the writer. Returns true on success.
+  bool Write(IMkvWriter* writer) const;
+
+ private:
+  // Expands the tags_ array if there is not enough space to contain
+  // another tag object.  Returns true on success.
+  bool ExpandTagsArray();
+
+  // Total length of the tags_ array.
+  int tags_size_;
+
+  // Number of active tags on the tags_ array.
+  int tags_count_;
+
+  // Array for storage of tag objects.
+  Tag* tags_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tags);
+};
+
+///////////////////////////////////////////////////////////////
+// Cluster element
+//
+// Notes:
+//  |Init| must be called before any other method in this class.
+class Cluster {
+ public:
+  // |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_t timecode, int64_t cues_pos, uint64_t timecode_scale,
+          bool write_last_frame_with_duration = false);
+  ~Cluster();
+
+  bool Init(IMkvWriter* ptr_writer);
+
+  // Adds a frame to be output in the file. The frame is written out through
+  // |writer_| if successful. Returns true on success.
+  bool AddFrame(const Frame* frame);
+
+  // Adds a frame to be output in the file. The frame is written out through
+  // |writer_| if successful. Returns true on success.
+  // Inputs:
+  //   data: Pointer to the data
+  //   length: Length of the data
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.  The range of allowed values is [1, 126].
+  //   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_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
+  // |writer_| if successful. Returns true on success.
+  // Inputs:
+  //   data: Pointer to the data
+  //   length: Length of the data
+  //   additional: Pointer to the additional data
+  //   additional_length: Length of the additional data
+  //   add_id: Value of BlockAddID element
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.  The range of allowed values is [1, 126].
+  //   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_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.
+  // Inputs:
+  //   data: Pointer to the data.
+  //   length: Length of the data.
+  //   discard_padding: DiscardPadding element value.
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.  The range of allowed values is [1, 126].
+  //   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_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.
+  // Inputs:
+  //   data: Pointer to the data
+  //   length: Length of the data
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.  The range of allowed values is [1, 126].
+  //   timecode:     Absolute (not relative to cluster) timestamp of the
+  //                 metadata frame, expressed in timecode units.
+  //   duration:     Duration of metadata frame, in timecode units.
+  //
+  // 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_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_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.
+  // 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_t Size() const;
+
+  // Given |abs_timecode|, calculates timecode relative to most recent timecode.
+  // Returns -1 on failure, or a relative timecode.
+  int64_t GetRelativeTimecode(int64_t abs_timecode) const;
+
+  int64_t size_position() const { return size_position_; }
+  int32_t blocks_added() const { return blocks_added_; }
+  uint64_t payload_size() const { return payload_size_; }
+  int64_t position_for_cues() const { return position_for_cues_; }
+  uint64_t timecode() const { return timecode_; }
+  uint64_t timecode_scale() const { return timecode_scale_; }
+  void set_write_last_frame_with_duration(bool write_last_frame_with_duration) {
+    write_last_frame_with_duration_ = write_last_frame_with_duration;
+  }
+  bool write_last_frame_with_duration() const {
+    return write_last_frame_with_duration_;
+  }
+
+ private:
+  // Iterator type for the |stored_frames_| map.
+  typedef std::map<uint64_t, std::list<Frame*> >::iterator FrameMapIterator;
+
+  // Utility method that confirms that blocks can still be added, and that the
+  // cluster header has been written. Used by |DoWriteFrame*|. Returns true
+  // when successful.
+  bool PreWriteBlock();
+
+  // Utility method used by the |DoWriteFrame*| methods that handles the book
+  // keeping required after each block is written.
+  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_t blocks_added_;
+
+  // Flag telling if the cluster has been closed.
+  bool finalized_;
+
+  // Flag telling if the cluster's header has been written.
+  bool header_written_;
+
+  // The size of the cluster elements in bytes.
+  uint64_t payload_size_;
+
+  // The file position used for cue points.
+  const int64_t position_for_cues_;
+
+  // The file position of the cluster's size element.
+  int64_t size_position_;
+
+  // The absolute timecode of the cluster.
+  const uint64_t timecode_;
+
+  // The timecode scale of the Segment containing the cluster.
+  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_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cluster);
+};
+
+///////////////////////////////////////////////////////////////
+// SeekHead element
+class SeekHead {
+ public:
+  SeekHead();
+  ~SeekHead();
+
+  // TODO(fgalligan): Change this to reserve a certain size. Then check how
+  // big the seek entry to be added is as not every seek entry will be the
+  // maximum size it could be.
+  // 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_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_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_t GetPosition(int index) const;
+
+  // Sets the Seek Entry id and position at given index.
+  // Returns true on success.
+  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_t kSeekEntryCount = 5;
+
+ private:
+  // Returns the maximum size in bytes of one seek entry.
+  uint64_t MaxEntrySize() const;
+
+  // Seek entry id element list.
+  uint32_t seek_entry_id_[kSeekEntryCount];
+
+  // Seek entry pos element list.
+  uint64_t seek_entry_pos_[kSeekEntryCount];
+
+  // The file position of SeekHead element.
+  int64_t start_pos_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
+};
+
+///////////////////////////////////////////////////////////////
+// Segment Information element
+class SegmentInfo {
+ public:
+  SegmentInfo();
+  ~SegmentInfo();
+
+  // Will update the duration if |duration_| is > 0.0. Returns true on success.
+  bool Finalize(IMkvWriter* writer) const;
+
+  // Sets |muxing_app_| and |writing_app_|.
+  bool Init();
+
+  // Output the Segment Information element to the writer. Returns true on
+  // success.
+  bool Write(IMkvWriter* writer);
+
+  void set_duration(double duration) { duration_ = duration; }
+  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_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_t date_utc) { date_utc_ = date_utc; }
+  int64_t date_utc() const { return date_utc_; }
+
+ private:
+  // Segment Information element names.
+  // Initially set to -1 to signify that a duration has not been set and should
+  // not be written out.
+  double duration_;
+  // Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
+  char* muxing_app_;
+  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_t date_utc_;
+
+  // The file position of the duration element.
+  int64_t duration_pos_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
+};
+
+///////////////////////////////////////////////////////////////
+// This class represents the main segment in a WebM file. Currently only
+// supports one Segment element.
+//
+// Notes:
+//  |Init| must be called before any other method in this class.
+class Segment {
+ public:
+  enum Mode { kLive = 0x1, kFile = 0x2 };
+
+  enum CuesPosition {
+    kAfterClusters = 0x0,  // Position Cues after Clusters - Default
+    kBeforeClusters = 0x1  // Position Cues before Clusters
+  };
+
+  const static uint32_t kDefaultDocTypeVersion = 2;
+  const static uint64_t kDefaultMaxClusterDuration = 30000000000ULL;
+
+  Segment();
+  ~Segment();
+
+  // Initializes |SegmentInfo| and returns result. Always returns false when
+  // |ptr_writer| is NULL.
+  bool Init(IMkvWriter* ptr_writer);
+
+  // Adds a generic track to the segment.  Returns the newly-allocated
+  // track object (which is owned by the segment) on success, NULL on
+  // 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_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_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
+  // populate its fields via the Chapter member functions.
+  Chapter* AddChapter();
+
+  // Adds an empty tag to the tags of this segment.  Returns
+  // non-NULL on success.  After adding the tag, the caller should
+  // populate its fields via the Tag member functions.
+  Tag* AddTag();
+
+  // Adds a cue point to the Cues element. |timestamp| is the time in
+  // 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_t timestamp, uint64_t track);
+
+  // Adds a frame to be output in the file. Returns true on success.
+  // Inputs:
+  //   data: Pointer to the data
+  //   length: Length of the data
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 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_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.
+  // Inputs:
+  //   data: Pointer to the data
+  //   length: Length of the data
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.
+  //   timecode:     Absolute timestamp of the metadata frame, expressed
+  //                 in nanosecond units.
+  //   duration:     Duration of metadata frame, in nanosecond units.
+  //
+  // 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_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.
+  // Inputs:
+  //   data: Pointer to the data.
+  //   length: Length of the data.
+  //   additional: Pointer to additional data.
+  //   additional_length: Length of additional data.
+  //   add_id: Additional ID which identifies the type of additional data.
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.
+  //   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_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.
+  // Inputs:
+  //   data: Pointer to the data.
+  //   length: Length of the data.
+  //   discard_padding: DiscardPadding element value.
+  //   track_number: Track to add the data to. Value returned by Add track
+  //                 functions.
+  //   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_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.
+  // Inputs:
+  //   frame: frame object
+  bool AddGenericFrame(const Frame* frame);
+
+  // Adds a VP8 video track to the segment. Returns the number of the track on
+  // 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_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
+  // writer is not seekable of if chunking is set to true.
+  // Input parameters:
+  // reader - an IMkvReader object created with the same underlying file of the
+  //          current writer object. Make sure to close the existing writer
+  //          object before creating this so that all the data is properly
+  //          flushed and available for reading.
+  // writer - an IMkvWriter object pointing to a *different* file than the one
+  //          pointed by the current writer object. This file will contain the
+  //          Cues element before the Clusters.
+  bool CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
+                                     IMkvWriter* writer);
+
+  // 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_t track_number);
+
+  // This will force the muxer to create a new Cluster when the next frame is
+  // added.
+  void ForceNewClusterOnNextFrame();
+
+  // Writes out any frames that have not been written out. Finalizes the last
+  // cluster. May update the size and duration of the segment. May output the
+  // Cues element. May finalize the SeekHead element. Returns true on success.
+  bool Finalize();
+
+  // Returns the Cues object.
+  Cues* GetCues() { return &cues_; }
+
+  // Returns the Segment Information object.
+  const SegmentInfo* GetSegmentInfo() const { return &segment_info_; }
+  SegmentInfo* GetSegmentInfo() { return &segment_info_; }
+
+  // Search the Tracks and return the track that matches |track_number|.
+  // Returns NULL if there is no track match.
+  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);
+
+  // 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
+  // |filename|.hdr and the data chunks will be named
+  // |filename|_XXXXXX.chk. Chunking implies that the muxer will be writing
+  // to files so the muxer will use the default MkvWriter class to control
+  // what data is written to what files. Returns true on success.
+  // TODO: Should we change the IMkvWriter Interface to add Open and Close?
+  // That will force the interface to be dependent on files.
+  bool SetChunking(bool chunking, const char* filename);
+
+  bool chunking() const { return chunking_; }
+  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_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_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_; }
+  bool output_cues() const { return output_cues_; }
+  const SegmentInfo* segment_info() const { return &segment_info_; }
+
+ private:
+  // Checks if header information has been output and initialized. If not it
+  // will output the Segment element and initialize the SeekHead elment and
+  // Cues elements.
+  bool CheckHeaderInfo();
+
+  // Sets |doc_type_version_| based on the current element requirements.
+  void UpdateDocTypeVersion();
+
+  // Sets |name| according to how many chunks have been written. |ext| is the
+  // file extension. |name| must be deleted by the calling app. Returns true
+  // on success.
+  bool UpdateChunkName(const char* ext, char** name) const;
+
+  // 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_t MaxOffset();
+
+  // Adds the frame to our frame array.
+  bool QueueFrame(Frame* frame);
+
+  // Output all frames that are queued. Returns -1 on error, otherwise
+  // it returns the number of frames written.
+  int WriteFramesAll();
+
+  // 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_t timestamp);
+
+  // Outputs the segment header, Segment Information element, SeekHead element,
+  // and Tracks element to |writer_|.
+  bool WriteSegmentHeader();
+
+  // Given a frame with the specified timestamp (nanosecond units) and
+  // keyframe status, determine whether a new cluster should be
+  // created, before writing enqueued frames and the frame itself. The
+  // function returns one of the following values:
+  //  -1 = error: an out-of-order frame was detected
+  //  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_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_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_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.
+  void MoveCuesBeforeClusters();
+
+  // This function recursively computes the correct cluster offsets (this is
+  // done to move the Cues before Clusters). It recursively updates the change
+  // in size (which indicates a change in cluster offset) until no sizes change.
+  // Parameters:
+  // diff - indicates the difference in size of the Cues element that needs to
+  //        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_t diff, int index,
+                                    uint64_t* cue_size);
+
+  // Seeds the random number generator used to make UIDs.
+  unsigned int seed_;
+
+  // WebM elements
+  Cues cues_;
+  SeekHead seek_head_;
+  SegmentInfo segment_info_;
+  Tracks tracks_;
+  Chapters chapters_;
+  Tags tags_;
+
+  // Number of chunks written.
+  int chunk_count_;
+
+  // Current chunk filename.
+  char* chunk_name_;
+
+  // Default MkvWriter object created by this class used for writing clusters
+  // out in separate files.
+  MkvWriter* chunk_writer_cluster_;
+
+  // Default MkvWriter object created by this class used for writing Cues
+  // element out to a file.
+  MkvWriter* chunk_writer_cues_;
+
+  // Default MkvWriter object created by this class used for writing the
+  // Matroska header out to a file.
+  MkvWriter* chunk_writer_header_;
+
+  // Flag telling whether or not the muxer is chunking output to multiple
+  // files.
+  bool chunking_;
+
+  // Base filename for the chunked files.
+  char* chunking_base_name_;
+
+  // File position offset where the Clusters end.
+  int64_t cluster_end_offset_;
+
+  // List of clusters.
+  Cluster** cluster_list_;
+
+  // Number of cluster pointers allocated in the cluster list.
+  int32_t cluster_list_capacity_;
+
+  // Number of clusters in the cluster list.
+  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_t cues_track_;
+
+  // Tells the muxer to force a new cluster on the next Block.
+  bool force_new_cluster_;
+
+  // List of stored audio frames. These variables are used to store frames so
+  // the muxer can follow the guideline "Audio blocks that contain the video
+  // key frame's timecode should be in the same cluster as the video key frame
+  // block."
+  Frame** frames_;
+
+  // Number of frame pointers allocated in the frame list.
+  int32_t frames_capacity_;
+
+  // Number of frames in the frame list.
+  int32_t frames_size_;
+
+  // Flag telling if a video track has been added to the segment.
+  bool has_video_;
+
+  // Flag telling if the segment's header has been written.
+  bool header_written_;
+
+  // Duration of the last block in nanoseconds.
+  uint64_t last_block_duration_;
+
+  // Last timestamp in nanoseconds added to a cluster.
+  uint64_t last_timestamp_;
+
+  // Last timestamp in nanoseconds by track number added to a cluster.
+  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_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_t max_cluster_size_;
+
+  // The mode that segment is in. If set to |kLive| the writer must not
+  // seek backwards.
+  Mode mode_;
+
+  // Flag telling the muxer that a new cue point should be added.
+  bool new_cuepoint_;
+
+  // TODO(fgalligan): Should we add support for more than one Cues element?
+  // 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_;
+
+  // The size of the EBML header, used to validate the header if
+  // WriteEbmlHeader() is called more than once.
+  int32_t ebml_header_size_;
+
+  // The file position of the segment's payload.
+  int64_t payload_pos_;
+
+  // The file position of the element's size.
+  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_t doc_type_version_;
+  uint32_t doc_type_version_written_;
+
+  // Pointer to the writer objects. Not owned by this class.
+  IMkvWriter* writer_cluster_;
+  IMkvWriter* writer_cues_;
+  IMkvWriter* writer_header_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
+};
+
+}  // namespace mkvmuxer
+
+#endif  // MKVMUXER_MKVMUXER_H_
\ No newline at end of file
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxertypes.h
@@ -1,0 +1,19 @@
+// 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_MKVMUXERTYPES_H_
+#define MKVMUXER_MKVMUXERTYPES_H_
+
+// Copied from Chromium basictypes.h
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);                       \
+  void operator=(const TypeName&)
+
+#endif  // MKVMUXER_MKVMUXERTYPES_HPP_
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
@@ -1,0 +1,635 @@
+// 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 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 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 ebml_size;
+}
+
+uint64_t EbmlElementSize(uint64_t type, uint64_t value) {
+  // Size of EBML ID
+  int32_t ebml_size = GetUIntSize(type);
+
+  // Datasize
+  ebml_size += 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 = 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 = 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 = 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 = 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) {
+  if (!writer)
+    return false;
+
+  if (WriteID(writer, type))
+    return false;
+
+  const uint64_t size = GetUIntSize(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, 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
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvmuxerutil.h
@@ -1,0 +1,83 @@
+// 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);
+
+// 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 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_
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.cc
@@ -1,0 +1,88 @@
+// 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/mkvwriter.h"
+
+#ifdef _MSC_VER
+#include <share.h>  // for _SH_DENYWR
+#endif
+
+namespace mkvmuxer {
+
+MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}
+
+MkvWriter::MkvWriter(FILE* fp) : file_(fp), writer_owns_file_(false) {}
+
+MkvWriter::~MkvWriter() { Close(); }
+
+int32_t MkvWriter::Write(const void* buffer, uint32_t length) {
+  if (!file_)
+    return -1;
+
+  if (length == 0)
+    return 0;
+
+  if (buffer == NULL)
+    return -1;
+
+  const size_t bytes_written = fwrite(buffer, 1, length, file_);
+
+  return (bytes_written == length) ? 0 : -1;
+}
+
+bool MkvWriter::Open(const char* filename) {
+  if (filename == NULL)
+    return false;
+
+  if (file_)
+    return false;
+
+#ifdef _MSC_VER
+  file_ = _fsopen(filename, "wb", _SH_DENYWR);
+#else
+  file_ = fopen(filename, "wb");
+#endif
+  if (file_ == NULL)
+    return false;
+  return true;
+}
+
+void MkvWriter::Close() {
+  if (file_ && writer_owns_file_) {
+    fclose(file_);
+  }
+  file_ = NULL;
+}
+
+int64_t MkvWriter::Position() const {
+  if (!file_)
+    return 0;
+
+#ifdef _MSC_VER
+  return _ftelli64(file_);
+#else
+  return ftell(file_);
+#endif
+}
+
+int32_t MkvWriter::Position(int64_t position) {
+  if (!file_)
+    return -1;
+
+#ifdef _MSC_VER
+  return _fseeki64(file_, position, SEEK_SET);
+#else
+  return fseek(file_, position, SEEK_SET);
+#endif
+}
+
+bool MkvWriter::Seekable() const { return true; }
+
+void MkvWriter::ElementStartNotify(uint64_t, int64_t) {}
+
+}  // namespace mkvmuxer
--- /dev/null
+++ b/third_party/libwebm/mkvmuxer/mkvwriter.h
@@ -1,0 +1,51 @@
+// 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_MKVWRITER_H_
+#define MKVMUXER_MKVWRITER_H_
+
+#include <stdio.h>
+
+#include "mkvmuxer/mkvmuxer.h"
+#include "mkvmuxer/mkvmuxertypes.h"
+
+namespace mkvmuxer {
+
+// Default implementation of the IMkvWriter interface on Windows.
+class MkvWriter : public IMkvWriter {
+ public:
+  MkvWriter();
+  explicit MkvWriter(FILE* fp);
+  virtual ~MkvWriter();
+
+  // IMkvWriter interface
+  virtual int64_t Position() const;
+  virtual int32_t Position(int64_t position);
+  virtual bool Seekable() const;
+  virtual int32_t Write(const void* buffer, uint32_t length);
+  virtual void ElementStartNotify(uint64_t element_id, int64_t position);
+
+  // Creates and opens a file for writing. |filename| is the name of the file
+  // to open. This function will overwrite the contents of |filename|. Returns
+  // true on success.
+  bool Open(const char* filename);
+
+  // Closes an opened file.
+  void Close();
+
+ private:
+  // File handle to output file.
+  FILE* file_;
+  bool writer_owns_file_;
+
+  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
+};
+
+}  // namespace mkvmuxer
+
+#endif  // MKVMUXER_MKVWRITER_H_
--- a/third_party/libwebm/mkvmuxertypes.hpp
+++ /dev/null
@@ -1,30 +1,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 MKVMUXERTYPES_HPP
-#define MKVMUXERTYPES_HPP
-
-// Copied from Chromium basictypes.h
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);                       \
-  void operator=(const TypeName&)
-
-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
--- a/third_party/libwebm/mkvmuxerutil.cpp
+++ /dev/null
@@ -1,629 +1,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;
-}
--- a/third_party/libwebm/mkvmuxerutil.hpp
+++ /dev/null
@@ -1,83 +1,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
--- a/third_party/libwebm/mkvparser.cpp
+++ /dev/null
@@ -1,7724 +1,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 "mkvparser.hpp"
-
-#if defined(_MSC_VER) && _MSC_VER < 1800
-#include <float.h>  // _isnan() / _finite()
-#define MSC_COMPAT
-#endif
-
-#include <cassert>
-#include <climits>
-#include <cmath>
-#include <cstring>
-#include <new>
-
-#include "webmids.hpp"
-
-#ifdef _MSC_VER
-// Disable MSVC warnings that suggest making code non-portable.
-#pragma warning(disable : 4996)
-#endif
-
-namespace mkvparser {
-
-#ifdef MSC_COMPAT
-inline bool isnan(double val) { return !!_isnan(val); }
-inline bool isinf(double val) { return !_finite(val); }
-#else
-inline bool isnan(double val) { return std::isnan(val); }
-inline bool isinf(double val) { return std::isinf(val); }
-#endif  // MSC_COMPAT
-
-IMkvReader::~IMkvReader() {}
-
-template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
-                                             unsigned long long element_size) {
-  if (num_elements == 0 || element_size == 0)
-    return NULL;
-
-  const size_t kMaxAllocSize = 0x80000000;  // 2GiB
-  const unsigned long long num_bytes = num_elements * element_size;
-  if (element_size > (kMaxAllocSize / num_elements))
-    return NULL;
-  if (num_bytes != static_cast<size_t>(num_bytes))
-    return NULL;
-
-  return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
-}
-
-void GetVersion(int& major, int& minor, int& build, int& revision) {
-  major = 1;
-  minor = 0;
-  build = 0;
-  revision = 30;
-}
-
-long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
-  if (!pReader || pos < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  len = 1;
-  unsigned char b;
-  int status = pReader->Read(pos, 1, &b);
-
-  if (status < 0)  // error or underflow
-    return status;
-
-  if (status > 0)  // interpreted as "underflow"
-    return E_BUFFER_NOT_FULL;
-
-  if (b == 0)  // we can't handle u-int values larger than 8 bytes
-    return E_FILE_FORMAT_INVALID;
-
-  unsigned char m = 0x80;
-
-  while (!(b & m)) {
-    m >>= 1;
-    ++len;
-  }
-
-  long long result = b & (~m);
-  ++pos;
-
-  for (int i = 1; i < len; ++i) {
-    status = pReader->Read(pos, 1, &b);
-
-    if (status < 0) {
-      len = 1;
-      return status;
-    }
-
-    if (status > 0) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result <<= 8;
-    result |= b;
-
-    ++pos;
-  }
-
-  return result;
-}
-
-// Reads an EBML ID and returns it.
-// An ID must at least 1 byte long, cannot exceed 4, and its value must be
-// greater than 0.
-// See known EBML values and EBMLMaxIDLength:
-// http://www.matroska.org/technical/specs/index.html
-// Returns the ID, or a value less than 0 to report an error while reading the
-// ID.
-long long ReadID(IMkvReader* pReader, long long pos, long& len) {
-  if (pReader == NULL || pos < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  // Read the first byte. The length in bytes of the ID is determined by
-  // finding the first set bit in the first byte of the ID.
-  unsigned char temp_byte = 0;
-  int read_status = pReader->Read(pos, 1, &temp_byte);
-
-  if (read_status < 0)
-    return E_FILE_FORMAT_INVALID;
-  else if (read_status > 0)  // No data to read.
-    return E_BUFFER_NOT_FULL;
-
-  if (temp_byte == 0)  // ID length > 8 bytes; invalid file.
-    return E_FILE_FORMAT_INVALID;
-
-  int bit_pos = 0;
-  const int kMaxIdLengthInBytes = 4;
-  const int kCheckByte = 0x80;
-
-  // Find the first bit that's set.
-  bool found_bit = false;
-  for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
-    if ((kCheckByte >> bit_pos) & temp_byte) {
-      found_bit = true;
-      break;
-    }
-  }
-
-  if (!found_bit) {
-    // The value is too large to be a valid ID.
-    return E_FILE_FORMAT_INVALID;
-  }
-
-  // Read the remaining bytes of the ID (if any).
-  const int id_length = bit_pos + 1;
-  long long ebml_id = temp_byte;
-  for (int i = 1; i < id_length; ++i) {
-    ebml_id <<= 8;
-    read_status = pReader->Read(pos + i, 1, &temp_byte);
-
-    if (read_status < 0)
-      return E_FILE_FORMAT_INVALID;
-    else if (read_status > 0)
-      return E_BUFFER_NOT_FULL;
-
-    ebml_id |= temp_byte;
-  }
-
-  len = id_length;
-  return ebml_id;
-}
-
-long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
-  if (!pReader || pos < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  long long total, available;
-
-  int status = pReader->Length(&total, &available);
-  if (status < 0 || (total >= 0 && available > total))
-    return E_FILE_FORMAT_INVALID;
-
-  len = 1;
-
-  if (pos >= available)
-    return pos;  // too few bytes available
-
-  unsigned char b;
-
-  status = pReader->Read(pos, 1, &b);
-
-  if (status != 0)
-    return status;
-
-  if (b == 0)  // we can't handle u-int values larger than 8 bytes
-    return E_FILE_FORMAT_INVALID;
-
-  unsigned char m = 0x80;
-
-  while (!(b & m)) {
-    m >>= 1;
-    ++len;
-  }
-
-  return 0;  // success
-}
-
-// TODO(vigneshv): This function assumes that unsigned values never have their
-// high bit set.
-long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
-  if (!pReader || pos < 0 || (size <= 0) || (size > 8))
-    return E_FILE_FORMAT_INVALID;
-
-  long long result = 0;
-
-  for (long long i = 0; i < size; ++i) {
-    unsigned char b;
-
-    const long status = pReader->Read(pos, 1, &b);
-
-    if (status < 0)
-      return status;
-
-    result <<= 8;
-    result |= b;
-
-    ++pos;
-  }
-
-  return result;
-}
-
-long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
-                      double& result) {
-  if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
-    return E_FILE_FORMAT_INVALID;
-
-  const long size = static_cast<long>(size_);
-
-  unsigned char buf[8];
-
-  const int status = pReader->Read(pos, size, buf);
-
-  if (status < 0)  // error
-    return status;
-
-  if (size == 4) {
-    union {
-      float f;
-      unsigned long ff;
-    };
-
-    ff = 0;
-
-    for (int i = 0;;) {
-      ff |= buf[i];
-
-      if (++i >= 4)
-        break;
-
-      ff <<= 8;
-    }
-
-    result = f;
-  } else {
-    union {
-      double d;
-      unsigned long long dd;
-    };
-
-    dd = 0;
-
-    for (int i = 0;;) {
-      dd |= buf[i];
-
-      if (++i >= 8)
-        break;
-
-      dd <<= 8;
-    }
-
-    result = d;
-  }
-
-  if (mkvparser::isinf(result) || mkvparser::isnan(result))
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
-                    long long& result_ref) {
-  if (!pReader || pos < 0 || size < 1 || size > 8)
-    return E_FILE_FORMAT_INVALID;
-
-  signed char first_byte = 0;
-  const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
-
-  if (status < 0)
-    return status;
-
-  unsigned long long result = first_byte;
-  ++pos;
-
-  for (long i = 1; i < size; ++i) {
-    unsigned char b;
-
-    const long status = pReader->Read(pos, 1, &b);
-
-    if (status < 0)
-      return status;
-
-    result <<= 8;
-    result |= b;
-
-    ++pos;
-  }
-
-  result_ref = static_cast<long long>(result);
-  return 0;
-}
-
-long UnserializeString(IMkvReader* pReader, long long pos, long long size,
-                       char*& str) {
-  delete[] str;
-  str = NULL;
-
-  if (size >= LONG_MAX || size < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  // +1 for '\0' terminator
-  const long required_size = static_cast<long>(size) + 1;
-
-  str = SafeArrayAlloc<char>(1, required_size);
-  if (str == NULL)
-    return E_FILE_FORMAT_INVALID;
-
-  unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
-
-  const long status = pReader->Read(pos, static_cast<long>(size), buf);
-
-  if (status) {
-    delete[] str;
-    str = NULL;
-
-    return status;
-  }
-
-  str[required_size - 1] = '\0';
-  return 0;
-}
-
-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;
-
-  long len;
-
-  id = ReadID(pReader, pos, len);
-
-  if (id < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume id
-
-  if (stop >= 0 && pos >= stop)
-    return E_FILE_FORMAT_INVALID;
-
-  size = ReadUInt(pReader, pos, len);
-
-  if (size < 0 || len < 1 || len > 8) {
-    // Invalid: Negative payload size, negative or 0 length integer, or integer
-    // larger than 64 bits (libwebm cannot handle them).
-    return E_FILE_FORMAT_INVALID;
-  }
-
-  // Avoid rolling over pos when very close to LLONG_MAX.
-  const unsigned long long rollover_check =
-      static_cast<unsigned long long>(pos) + len;
-  if (rollover_check > LLONG_MAX)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume length of size
-
-  // pos now designates payload
-
-  if (stop >= 0 && pos >= stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;  // success
-}
-
-bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
-           long long& val) {
-  if (!pReader || pos < 0)
-    return false;
-
-  long long total = 0;
-  long long available = 0;
-
-  const long status = pReader->Length(&total, &available);
-  if (status < 0 || (total >= 0 && available > total))
-    return false;
-
-  long len = 0;
-
-  const long long id = ReadID(pReader, pos, len);
-  if (id < 0 || (available - pos) > len)
-    return false;
-
-  if (static_cast<unsigned long>(id) != expected_id)
-    return false;
-
-  pos += len;  // consume id
-
-  const long long size = ReadUInt(pReader, pos, len);
-  if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
-    return false;
-
-  pos += len;  // consume length of size of payload
-
-  val = UnserializeUInt(pReader, pos, size);
-  if (val < 0)
-    return false;
-
-  pos += size;  // consume size of payload
-
-  return true;
-}
-
-bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
-           unsigned char*& buf, size_t& buflen) {
-  if (!pReader || pos < 0)
-    return false;
-
-  long long total = 0;
-  long long available = 0;
-
-  long status = pReader->Length(&total, &available);
-  if (status < 0 || (total >= 0 && available > total))
-    return false;
-
-  long len = 0;
-  const long long id = ReadID(pReader, pos, len);
-  if (id < 0 || (available - pos) > len)
-    return false;
-
-  if (static_cast<unsigned long>(id) != expected_id)
-    return false;
-
-  pos += len;  // consume id
-
-  const long long size = ReadUInt(pReader, pos, len);
-  if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
-    return false;
-
-  unsigned long long rollover_check =
-      static_cast<unsigned long long>(pos) + len;
-  if (rollover_check > LLONG_MAX)
-    return false;
-
-  pos += len;  // consume length of size of payload
-
-  rollover_check = static_cast<unsigned long long>(pos) + size;
-  if (rollover_check > LLONG_MAX)
-    return false;
-
-  if ((pos + size) > available)
-    return false;
-
-  if (size >= LONG_MAX)
-    return false;
-
-  const long buflen_ = static_cast<long>(size);
-
-  buf = SafeArrayAlloc<unsigned char>(1, buflen_);
-  if (!buf)
-    return false;
-
-  status = pReader->Read(pos, buflen_, buf);
-  if (status != 0)
-    return false;
-
-  buflen = buflen_;
-
-  pos += size;  // consume size of payload
-  return true;
-}
-
-EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
-
-EBMLHeader::~EBMLHeader() { delete[] m_docType; }
-
-void EBMLHeader::Init() {
-  m_version = 1;
-  m_readVersion = 1;
-  m_maxIdLength = 4;
-  m_maxSizeLength = 8;
-
-  if (m_docType) {
-    delete[] m_docType;
-    m_docType = NULL;
-  }
-
-  m_docTypeVersion = 1;
-  m_docTypeReadVersion = 1;
-}
-
-long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
-  if (!pReader)
-    return E_FILE_FORMAT_INVALID;
-
-  long long total, available;
-
-  long status = pReader->Length(&total, &available);
-
-  if (status < 0)  // error
-    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;
-  const unsigned char kEbmlByte0 = 0x1A;
-  unsigned char scan_byte = 0;
-
-  while (pos < kMaxScanBytes) {
-    status = pReader->Read(pos, 1, &scan_byte);
-
-    if (status < 0)  // error
-      return status;
-    else if (status > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if (scan_byte == kEbmlByte0)
-      break;
-
-    ++pos;
-  }
-
-  long len = 0;
-  const long long ebml_id = ReadID(pReader, pos, len);
-
-  // TODO(tomfinegan): Move Matroska ID constants into a common namespace.
-  if (len != 4 || ebml_id != mkvmuxer::kMkvEBML)
-    return E_FILE_FORMAT_INVALID;
-
-  // Move read pos forward to the EBML header size field.
-  pos += 4;
-
-  // Read length of size field.
-  long long result = GetUIntLength(pReader, pos, len);
-
-  if (result < 0)  // error
-    return E_FILE_FORMAT_INVALID;
-  else if (result > 0)  // need more data
-    return E_BUFFER_NOT_FULL;
-
-  if (len < 1 || len > 8)
-    return E_FILE_FORMAT_INVALID;
-
-  if ((total >= 0) && ((total - pos) < len))
-    return E_FILE_FORMAT_INVALID;
-
-  if ((available - pos) < len)
-    return pos + len;  // try again later
-
-  // Read the EBML header size.
-  result = ReadUInt(pReader, pos, len);
-
-  if (result < 0)  // error
-    return result;
-
-  pos += len;  // consume size field
-
-  // pos now designates start of payload
-
-  if ((total >= 0) && ((total - pos) < result))
-    return E_FILE_FORMAT_INVALID;
-
-  if ((available - pos) < result)
-    return pos + result;
-
-  end = pos + result;
-
-  Init();
-
-  while (pos < end) {
-    long long id, size;
-
-    status = ParseElementHeader(pReader, pos, end, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (id == mkvmuxer::kMkvEBMLVersion) {
-      m_version = UnserializeUInt(pReader, pos, size);
-
-      if (m_version <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLReadVersion) {
-      m_readVersion = UnserializeUInt(pReader, pos, size);
-
-      if (m_readVersion <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) {
-      m_maxIdLength = UnserializeUInt(pReader, pos, size);
-
-      if (m_maxIdLength <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) {
-      m_maxSizeLength = UnserializeUInt(pReader, pos, size);
-
-      if (m_maxSizeLength <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDocType) {
-      if (m_docType)
-        return E_FILE_FORMAT_INVALID;
-
-      status = UnserializeString(pReader, pos, size, m_docType);
-
-      if (status)  // error
-        return status;
-    } else if (id == mkvmuxer::kMkvDocTypeVersion) {
-      m_docTypeVersion = UnserializeUInt(pReader, pos, size);
-
-      if (m_docTypeVersion <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDocTypeReadVersion) {
-      m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
-
-      if (m_docTypeReadVersion <= 0)
-        return E_FILE_FORMAT_INVALID;
-    }
-
-    pos += size;
-  }
-
-  if (pos != end)
-    return E_FILE_FORMAT_INVALID;
-
-  // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
-  if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
-    return E_FILE_FORMAT_INVALID;
-
-  // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
-  if (m_maxIdLength <= 0 || m_maxIdLength > 4 ||
-      m_maxSizeLength <= 0 || m_maxSizeLength > 8)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-Segment::Segment(IMkvReader* pReader, long long elem_start,
-                 // long long elem_size,
-                 long long start, long long size)
-    : m_pReader(pReader),
-      m_element_start(elem_start),
-      // m_element_size(elem_size),
-      m_start(start),
-      m_size(size),
-      m_pos(start),
-      m_pUnknownSize(0),
-      m_pSeekHead(NULL),
-      m_pInfo(NULL),
-      m_pTracks(NULL),
-      m_pCues(NULL),
-      m_pChapters(NULL),
-      m_pTags(NULL),
-      m_clusters(NULL),
-      m_clusterCount(0),
-      m_clusterPreloadCount(0),
-      m_clusterSize(0) {}
-
-Segment::~Segment() {
-  const long count = m_clusterCount + m_clusterPreloadCount;
-
-  Cluster** i = m_clusters;
-  Cluster** j = m_clusters + count;
-
-  while (i != j) {
-    Cluster* const p = *i++;
-    delete p;
-  }
-
-  delete[] m_clusters;
-
-  delete m_pTracks;
-  delete m_pInfo;
-  delete m_pCues;
-  delete m_pChapters;
-  delete m_pTags;
-  delete m_pSeekHead;
-}
-
-long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
-                                  Segment*& pSegment) {
-  if (pReader == NULL || pos < 0)
-    return E_PARSE_FAILED;
-
-  pSegment = NULL;
-
-  long long total, available;
-
-  const long status = pReader->Length(&total, &available);
-
-  if (status < 0)  // error
-    return status;
-
-  if (available < 0)
-    return -1;
-
-  if ((total >= 0) && (available > total))
-    return -1;
-
-  // I would assume that in practice this loop would execute
-  // exactly once, but we allow for other elements (e.g. Void)
-  // to immediately follow the EBML header.  This is fine for
-  // the source filter case (since the entire file is available),
-  // but in the splitter case over a network we should probably
-  // just give up early.  We could for example decide only to
-  // execute this loop a maximum of, say, 10 times.
-  // TODO:
-  // There is an implied "give up early" by only parsing up
-  // to the available limit.  We do do that, but only if the
-  // total file size is unknown.  We could decide to always
-  // use what's available as our limit (irrespective of whether
-  // we happen to know the total file length).  This would have
-  // as its sense "parse this much of the file before giving up",
-  // which a slightly different sense from "try to parse up to
-  // 10 EMBL elements before giving up".
-
-  for (;;) {
-    if ((total >= 0) && (pos >= total))
-      return E_FILE_FORMAT_INVALID;
-
-    // Read ID
-    long len;
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result)  // error, or too few available bytes
-      return result;
-
-    if ((total >= 0) && ((pos + len) > total))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > available)
-      return pos + len;
-
-    const long long idpos = pos;
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume ID
-
-    // Read Size
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result)  // error, or too few available bytes
-      return result;
-
-    if ((total >= 0) && ((pos + len) > total))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > available)
-      return pos + len;
-
-    long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return size;
-
-    pos += len;  // consume length of size of element
-
-    // Pos now points to start of payload
-
-    // Handle "unknown size" for live streaming of webm files.
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (id == mkvmuxer::kMkvSegment) {
-      if (size == unknown_size)
-        size = -1;
-
-      else if (total < 0)
-        size = -1;
-
-      else if ((pos + size) > total)
-        size = -1;
-
-      pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
-      if (pSegment == NULL)
-        return E_PARSE_FAILED;
-
-      return 0;  // success
-    }
-
-    if (size == unknown_size)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((total >= 0) && ((pos + size) > total))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + size) > available)
-      return pos + size;
-
-    pos += size;  // consume payload
-  }
-}
-
-long long Segment::ParseHeaders() {
-  // Outermost (level 0) segment object has been constructed,
-  // and pos designates start of payload.  We need to find the
-  // inner (level 1) elements.
-  long long total, available;
-
-  const int status = m_pReader->Length(&total, &available);
-
-  if (status < 0)  // error
-    return status;
-
-  if (total > 0 && available > total)
-    return E_FILE_FORMAT_INVALID;
-
-  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
-
-  if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
-      (segment_stop >= 0 && m_pos > segment_stop)) {
-    return E_FILE_FORMAT_INVALID;
-  }
-
-  for (;;) {
-    if ((total >= 0) && (m_pos >= total))
-      break;
-
-    if ((segment_stop >= 0) && (m_pos >= segment_stop))
-      break;
-
-    long long pos = m_pos;
-    const long long element_start = pos;
-
-    // Avoid rolling over pos when very close to LLONG_MAX.
-    unsigned long long rollover_check = pos + 1ULL;
-    if (rollover_check > LLONG_MAX)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + 1) > available)
-      return (pos + 1);
-
-    long len;
-    long long result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return result;
-
-    if (result > 0) {
-      // MkvReader doesn't have enough data to satisfy this read attempt.
-      return (pos + 1);
-    }
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > available)
-      return pos + len;
-
-    const long long idpos = pos;
-    const long long id = ReadID(m_pReader, idpos, len);
-
-    if (id < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (id == mkvmuxer::kMkvCluster)
-      break;
-
-    pos += len;  // consume ID
-
-    if ((pos + 1) > available)
-      return (pos + 1);
-
-    // Read Size
-    result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return result;
-
-    if (result > 0) {
-      // MkvReader doesn't have enough data to satisfy this read attempt.
-      return (pos + 1);
-    }
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > available)
-      return pos + len;
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-
-    if (size < 0 || len < 1 || len > 8) {
-      // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
-      // len > 8 is true instead of checking this _everywhere_.
-      return size;
-    }
-
-    pos += len;  // consume length of size of element
-
-    // Avoid rolling over pos when very close to LLONG_MAX.
-    rollover_check = static_cast<unsigned long long>(pos) + size;
-    if (rollover_check > LLONG_MAX)
-      return E_FILE_FORMAT_INVALID;
-
-    const long long element_size = size + pos - element_start;
-
-    // Pos now points to start of payload
-
-    if ((segment_stop >= 0) && ((pos + size) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    // We read EBML elements either in total or nothing at all.
-
-    if ((pos + size) > available)
-      return pos + size;
-
-    if (id == mkvmuxer::kMkvInfo) {
-      if (m_pInfo)
-        return E_FILE_FORMAT_INVALID;
-
-      m_pInfo = new (std::nothrow)
-          SegmentInfo(this, pos, size, element_start, element_size);
-
-      if (m_pInfo == NULL)
-        return -1;
-
-      const long status = m_pInfo->Parse();
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvTracks) {
-      if (m_pTracks)
-        return E_FILE_FORMAT_INVALID;
-
-      m_pTracks = new (std::nothrow)
-          Tracks(this, pos, size, element_start, element_size);
-
-      if (m_pTracks == NULL)
-        return -1;
-
-      const long status = m_pTracks->Parse();
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvCues) {
-      if (m_pCues == NULL) {
-        m_pCues = new (std::nothrow)
-            Cues(this, pos, size, element_start, element_size);
-
-        if (m_pCues == NULL)
-          return -1;
-      }
-    } else if (id == mkvmuxer::kMkvSeekHead) {
-      if (m_pSeekHead == NULL) {
-        m_pSeekHead = new (std::nothrow)
-            SeekHead(this, pos, size, element_start, element_size);
-
-        if (m_pSeekHead == NULL)
-          return -1;
-
-        const long status = m_pSeekHead->Parse();
-
-        if (status)
-          return status;
-      }
-    } else if (id == mkvmuxer::kMkvChapters) {
-      if (m_pChapters == NULL) {
-        m_pChapters = new (std::nothrow)
-            Chapters(this, pos, size, element_start, element_size);
-
-        if (m_pChapters == NULL)
-          return -1;
-
-        const long status = m_pChapters->Parse();
-
-        if (status)
-          return status;
-      }
-    } else if (id == mkvmuxer::kMkvTags) {
-      if (m_pTags == NULL) {
-        m_pTags = new (std::nothrow)
-            Tags(this, pos, size, element_start, element_size);
-
-        if (m_pTags == NULL)
-          return -1;
-
-        const long status = m_pTags->Parse();
-
-        if (status)
-          return status;
-      }
-    }
-
-    m_pos = pos + size;  // consume payload
-  }
-
-  if (segment_stop >= 0 && m_pos > segment_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if (m_pInfo == NULL)  // TODO: liberalize this behavior
-    return E_FILE_FORMAT_INVALID;
-
-  if (m_pTracks == NULL)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;  // success
-}
-
-long Segment::LoadCluster(long long& pos, long& len) {
-  for (;;) {
-    const long result = DoLoadCluster(pos, len);
-
-    if (result <= 1)
-      return result;
-  }
-}
-
-long Segment::DoLoadCluster(long long& pos, long& len) {
-  if (m_pos < 0)
-    return DoLoadClusterUnknownSize(pos, len);
-
-  long long total, avail;
-
-  long status = m_pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  if (total >= 0 && avail > total)
-    return E_FILE_FORMAT_INVALID;
-
-  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
-
-  long long cluster_off = -1;  // offset relative to start of segment
-  long long cluster_size = -1;  // size of cluster payload
-
-  for (;;) {
-    if ((total >= 0) && (m_pos >= total))
-      return 1;  // no more clusters
-
-    if ((segment_stop >= 0) && (m_pos >= segment_stop))
-      return 1;  // no more clusters
-
-    pos = m_pos;
-
-    // Read ID
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long idpos = pos;
-    const long long id = ReadID(m_pReader, idpos, len);
-
-    if (id < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume ID
-
-    // Read Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    pos += len;  // consume length of size of element
-
-    // pos now points to start of payload
-
-    if (size == 0) {
-      // Missing element payload: move on.
-      m_pos = pos;
-      continue;
-    }
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if ((segment_stop >= 0) && (size != unknown_size) &&
-        ((pos + size) > segment_stop)) {
-      return E_FILE_FORMAT_INVALID;
-    }
-
-    if (id == mkvmuxer::kMkvCues) {
-      if (size == unknown_size) {
-        // Cues element of unknown size: Not supported.
-        return E_FILE_FORMAT_INVALID;
-      }
-
-      if (m_pCues == NULL) {
-        const long long element_size = (pos - idpos) + size;
-
-        m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
-        if (m_pCues == NULL)
-          return -1;
-      }
-
-      m_pos = pos + size;  // consume payload
-      continue;
-    }
-
-    if (id != mkvmuxer::kMkvCluster) {
-      // Besides the Segment, Libwebm allows only cluster elements of unknown
-      // size. Fail the parse upon encountering a non-cluster element reporting
-      // unknown size.
-      if (size == unknown_size)
-        return E_FILE_FORMAT_INVALID;
-
-      m_pos = pos + size;  // consume payload
-      continue;
-    }
-
-    // We have a cluster.
-
-    cluster_off = idpos - m_start;  // relative pos
-
-    if (size != unknown_size)
-      cluster_size = size;
-
-    break;
-  }
-
-  if (cluster_off < 0) {
-    // No cluster, die.
-    return E_FILE_FORMAT_INVALID;
-  }
-
-  long long pos_;
-  long len_;
-
-  status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
-
-  if (status < 0) {  // error, or underflow
-    pos = pos_;
-    len = len_;
-
-    return status;
-  }
-
-  // status == 0 means "no block entries found"
-  // status > 0 means "found at least one block entry"
-
-  // TODO:
-  // The issue here is that the segment increments its own
-  // pos ptr past the most recent cluster parsed, and then
-  // starts from there to parse the next cluster.  If we
-  // don't know the size of the current cluster, then we
-  // must either parse its payload (as we do below), looking
-  // for the cluster (or cues) ID to terminate the parse.
-  // This isn't really what we want: rather, we really need
-  // a way to create the curr cluster object immediately.
-  // The pity is that cluster::parse can determine its own
-  // boundary, and we largely duplicate that same logic here.
-  //
-  // Maybe we need to get rid of our look-ahead preloading
-  // in source::parse???
-  //
-  // As we're parsing the blocks in the curr cluster
-  //(in cluster::parse), we should have some way to signal
-  // to the segment that we have determined the boundary,
-  // so it can adjust its own segment::m_pos member.
-  //
-  // The problem is that we're asserting in asyncreadinit,
-  // because we adjust the pos down to the curr seek pos,
-  // and the resulting adjusted len is > 2GB.  I'm suspicious
-  // that this is even correct, but even if it is, we can't
-  // be loading that much data in the cache anyway.
-
-  const long idx = m_clusterCount;
-
-  if (m_clusterPreloadCount > 0) {
-    if (idx >= m_clusterSize)
-      return E_FILE_FORMAT_INVALID;
-
-    Cluster* const pCluster = m_clusters[idx];
-    if (pCluster == NULL || pCluster->m_index >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    const long long off = pCluster->GetPosition();
-    if (off < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (off == cluster_off) {  // preloaded already
-      if (status == 0)  // no entries found
-        return E_FILE_FORMAT_INVALID;
-
-      if (cluster_size >= 0)
-        pos += cluster_size;
-      else {
-        const long long element_size = pCluster->GetElementSize();
-
-        if (element_size <= 0)
-          return E_FILE_FORMAT_INVALID;  // TODO: handle this case
-
-        pos = pCluster->m_element_start + element_size;
-      }
-
-      pCluster->m_index = idx;  // move from preloaded to loaded
-      ++m_clusterCount;
-      --m_clusterPreloadCount;
-
-      m_pos = pos;  // consume payload
-      if (segment_stop >= 0 && m_pos > segment_stop)
-        return E_FILE_FORMAT_INVALID;
-
-      return 0;  // success
-    }
-  }
-
-  if (status == 0) {  // no entries found
-    if (cluster_size >= 0)
-      pos += cluster_size;
-
-    if ((total >= 0) && (pos >= total)) {
-      m_pos = total;
-      return 1;  // no more clusters
-    }
-
-    if ((segment_stop >= 0) && (pos >= segment_stop)) {
-      m_pos = segment_stop;
-      return 1;  // no more clusters
-    }
-
-    m_pos = pos;
-    return 2;  // try again
-  }
-
-  // status > 0 means we have an entry
-
-  Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
-  if (pCluster == NULL)
-    return -1;
-
-  if (!AppendCluster(pCluster)) {
-    delete pCluster;
-    return -1;
-  }
-
-  if (cluster_size >= 0) {
-    pos += cluster_size;
-
-    m_pos = pos;
-
-    if (segment_stop > 0 && m_pos > segment_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    return 0;
-  }
-
-  m_pUnknownSize = pCluster;
-  m_pos = -pos;
-
-  return 0;  // partial success, since we have a new cluster
-
-  // status == 0 means "no block entries found"
-  // pos designates start of payload
-  // m_pos has NOT been adjusted yet (in case we need to come back here)
-}
-
-long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
-  if (m_pos >= 0 || m_pUnknownSize == NULL)
-    return E_PARSE_FAILED;
-
-  const long status = m_pUnknownSize->Parse(pos, len);
-
-  if (status < 0)  // error or underflow
-    return status;
-
-  if (status == 0)  // parsed a block
-    return 2;  // continue parsing
-
-  const long long start = m_pUnknownSize->m_element_start;
-  const long long size = m_pUnknownSize->GetElementSize();
-
-  if (size < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  pos = start + size;
-  m_pos = pos;
-
-  m_pUnknownSize = 0;
-
-  return 2;  // continue parsing
-}
-
-bool Segment::AppendCluster(Cluster* pCluster) {
-  if (pCluster == NULL || pCluster->m_index < 0)
-    return false;
-
-  const long count = m_clusterCount + m_clusterPreloadCount;
-
-  long& size = m_clusterSize;
-  const long idx = pCluster->m_index;
-
-  if (size < count || idx != m_clusterCount)
-    return false;
-
-  if (count >= size) {
-    const long n = (size <= 0) ? 2048 : 2 * size;
-
-    Cluster** const qq = new (std::nothrow) Cluster*[n];
-    if (qq == NULL)
-      return false;
-
-    Cluster** q = qq;
-    Cluster** p = m_clusters;
-    Cluster** const pp = p + count;
-
-    while (p != pp)
-      *q++ = *p++;
-
-    delete[] m_clusters;
-
-    m_clusters = qq;
-    size = n;
-  }
-
-  if (m_clusterPreloadCount > 0) {
-    Cluster** const p = m_clusters + m_clusterCount;
-    if (*p == NULL || (*p)->m_index >= 0)
-      return false;
-
-    Cluster** q = p + m_clusterPreloadCount;
-    if (q >= (m_clusters + size))
-      return false;
-
-    for (;;) {
-      Cluster** const qq = q - 1;
-      if ((*qq)->m_index >= 0)
-        return false;
-
-      *q = *qq;
-      q = qq;
-
-      if (q == p)
-        break;
-    }
-  }
-
-  m_clusters[idx] = pCluster;
-  ++m_clusterCount;
-  return true;
-}
-
-bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
-  if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
-    return false;
-
-  const long count = m_clusterCount + m_clusterPreloadCount;
-
-  long& size = m_clusterSize;
-  if (size < count)
-    return false;
-
-  if (count >= size) {
-    const long n = (size <= 0) ? 2048 : 2 * size;
-
-    Cluster** const qq = new (std::nothrow) Cluster*[n];
-    if (qq == NULL)
-      return false;
-    Cluster** q = qq;
-
-    Cluster** p = m_clusters;
-    Cluster** const pp = p + count;
-
-    while (p != pp)
-      *q++ = *p++;
-
-    delete[] m_clusters;
-
-    m_clusters = qq;
-    size = n;
-  }
-
-  if (m_clusters == NULL)
-    return false;
-
-  Cluster** const p = m_clusters + idx;
-
-  Cluster** q = m_clusters + count;
-  if (q < p || q >= (m_clusters + size))
-    return false;
-
-  while (q > p) {
-    Cluster** const qq = q - 1;
-
-    if ((*qq)->m_index >= 0)
-      return false;
-
-    *q = *qq;
-    q = qq;
-  }
-
-  m_clusters[idx] = pCluster;
-  ++m_clusterPreloadCount;
-  return true;
-}
-
-long Segment::Load() {
-  if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
-    return E_PARSE_FAILED;
-
-  // Outermost (level 0) segment object has been constructed,
-  // and pos designates start of payload.  We need to find the
-  // inner (level 1) elements.
-
-  const long long header_status = ParseHeaders();
-
-  if (header_status < 0)  // error
-    return static_cast<long>(header_status);
-
-  if (header_status > 0)  // underflow
-    return E_BUFFER_NOT_FULL;
-
-  if (m_pInfo == NULL || m_pTracks == NULL)
-    return E_FILE_FORMAT_INVALID;
-
-  for (;;) {
-    const int status = LoadCluster();
-
-    if (status < 0)  // error
-      return status;
-
-    if (status >= 1)  // no more clusters
-      return 0;
-  }
-}
-
-SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
-                   long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_start(start),
-      m_size(size_),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_entries(0),
-      m_entry_count(0),
-      m_void_elements(0),
-      m_void_element_count(0) {}
-
-SeekHead::~SeekHead() {
-  delete[] m_entries;
-  delete[] m_void_elements;
-}
-
-long SeekHead::Parse() {
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = m_start;
-  const long long stop = m_start + m_size;
-
-  // first count the seek head entries
-
-  int entry_count = 0;
-  int void_element_count = 0;
-
-  while (pos < stop) {
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvSeek)
-      ++entry_count;
-    else if (id == mkvmuxer::kMkvVoid)
-      ++void_element_count;
-
-    pos += size;  // consume payload
-
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  m_entries = new (std::nothrow) Entry[entry_count];
-
-  if (m_entries == NULL)
-    return -1;
-
-  m_void_elements = new (std::nothrow) VoidElement[void_element_count];
-
-  if (m_void_elements == NULL)
-    return -1;
-
-  // now parse the entries and void elements
-
-  Entry* pEntry = m_entries;
-  VoidElement* pVoidElement = m_void_elements;
-
-  pos = m_start;
-
-  while (pos < stop) {
-    const long long idpos = pos;
-
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::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) {
-      VoidElement& e = *pVoidElement++;
-
-      e.element_start = idpos;
-      e.element_size = (pos + size) - idpos;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
-  assert(count_ >= 0);
-  assert(count_ <= entry_count);
-
-  m_entry_count = static_cast<int>(count_);
-
-  count_ = ptrdiff_t(pVoidElement - m_void_elements);
-  assert(count_ >= 0);
-  assert(count_ <= void_element_count);
-
-  m_void_element_count = static_cast<int>(count_);
-
-  return 0;
-}
-
-int SeekHead::GetCount() const { return m_entry_count; }
-
-const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
-  if (idx < 0)
-    return 0;
-
-  if (idx >= m_entry_count)
-    return 0;
-
-  return m_entries + idx;
-}
-
-int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
-
-const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
-  if (idx < 0)
-    return 0;
-
-  if (idx >= m_void_element_count)
-    return 0;
-
-  return m_void_elements + idx;
-}
-
-long Segment::ParseCues(long long off, long long& pos, long& len) {
-  if (m_pCues)
-    return 0;  // success
-
-  if (off < 0)
-    return -1;
-
-  long long total, avail;
-
-  const int status = m_pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  pos = m_start + off;
-
-  if ((total < 0) || (pos >= total))
-    return 1;  // don't bother parsing cues
-
-  const long long element_start = pos;
-  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  long long result = GetUIntLength(m_pReader, pos, len);
-
-  if (result < 0)  // error
-    return static_cast<long>(result);
-
-  if (result > 0)  // underflow (weird)
-  {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + len) > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long idpos = pos;
-
-  const long long id = ReadID(m_pReader, idpos, len);
-
-  if (id != mkvmuxer::kMkvCues)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume ID
-  assert((segment_stop < 0) || (pos <= segment_stop));
-
-  // Read Size
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  result = GetUIntLength(m_pReader, pos, len);
-
-  if (result < 0)  // error
-    return static_cast<long>(result);
-
-  if (result > 0)  // underflow (weird)
-  {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + len) > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long size = ReadUInt(m_pReader, pos, len);
-
-  if (size < 0)  // error
-    return static_cast<long>(size);
-
-  if (size == 0)  // weird, although technically not illegal
-    return 1;  // done
-
-  pos += len;  // consume length of size of element
-  assert((segment_stop < 0) || (pos <= segment_stop));
-
-  // Pos now points to start of payload
-
-  const long long element_stop = pos + size;
-
-  if ((segment_stop >= 0) && (element_stop > segment_stop))
-    return E_FILE_FORMAT_INVALID;
-
-  if ((total >= 0) && (element_stop > total))
-    return 1;  // don't bother parsing anymore
-
-  len = static_cast<long>(size);
-
-  if (element_stop > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long element_size = element_stop - element_start;
-
-  m_pCues =
-      new (std::nothrow) Cues(this, pos, size, element_start, element_size);
-  if (m_pCues == NULL)
-    return -1;
-
-  return 0;  // success
-}
-
-bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
-                          Entry* pEntry) {
-  if (size_ <= 0)
-    return false;
-
-  long long pos = start;
-  const long long stop = start + size_;
-
-  long len;
-
-  // parse the container for the level-1 element ID
-
-  const long long seekIdId = ReadID(pReader, pos, len);
-  if (seekIdId < 0)
-    return false;
-
-  if (seekIdId != mkvmuxer::kMkvSeekID)
-    return false;
-
-  if ((pos + len) > stop)
-    return false;
-
-  pos += len;  // consume SeekID id
-
-  const long long seekIdSize = ReadUInt(pReader, pos, len);
-
-  if (seekIdSize <= 0)
-    return false;
-
-  if ((pos + len) > stop)
-    return false;
-
-  pos += len;  // consume size of field
-
-  if ((pos + seekIdSize) > stop)
-    return false;
-
-  // Note that the SeekId payload really is serialized
-  // as a "Matroska integer", not as a plain binary value.
-  // In fact, Matroska requires that ID values in the
-  // stream exactly match the binary representation as listed
-  // in the Matroska specification.
-  //
-  // This parser is more liberal, and permits IDs to have
-  // any width.  (This could make the representation in the stream
-  // different from what's in the spec, but it doesn't matter here,
-  // since we always normalize "Matroska integer" values.)
-
-  pEntry->id = ReadUInt(pReader, pos, len);  // payload
-
-  if (pEntry->id <= 0)
-    return false;
-
-  if (len != seekIdSize)
-    return false;
-
-  pos += seekIdSize;  // consume SeekID payload
-
-  const long long seekPosId = ReadID(pReader, pos, len);
-
-  if (seekPosId != mkvmuxer::kMkvSeekPosition)
-    return false;
-
-  if ((pos + len) > stop)
-    return false;
-
-  pos += len;  // consume id
-
-  const long long seekPosSize = ReadUInt(pReader, pos, len);
-
-  if (seekPosSize <= 0)
-    return false;
-
-  if ((pos + len) > stop)
-    return false;
-
-  pos += len;  // consume size
-
-  if ((pos + seekPosSize) > stop)
-    return false;
-
-  pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
-
-  if (pEntry->pos < 0)
-    return false;
-
-  pos += seekPosSize;  // consume payload
-
-  if (pos != stop)
-    return false;
-
-  return true;
-}
-
-Cues::Cues(Segment* pSegment, long long start_, long long size_,
-           long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_start(start_),
-      m_size(size_),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_cue_points(NULL),
-      m_count(0),
-      m_preload_count(0),
-      m_pos(start_) {}
-
-Cues::~Cues() {
-  const long n = m_count + m_preload_count;
-
-  CuePoint** p = m_cue_points;
-  CuePoint** const q = p + n;
-
-  while (p != q) {
-    CuePoint* const pCP = *p++;
-    assert(pCP);
-
-    delete pCP;
-  }
-
-  delete[] m_cue_points;
-}
-
-long Cues::GetCount() const {
-  if (m_cue_points == NULL)
-    return -1;
-
-  return m_count;  // TODO: really ignore preload count?
-}
-
-bool Cues::DoneParsing() const {
-  const long long stop = m_start + m_size;
-  return (m_pos >= stop);
-}
-
-bool Cues::Init() const {
-  if (m_cue_points)
-    return true;
-
-  if (m_count != 0 || m_preload_count != 0)
-    return false;
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  const long long stop = m_start + m_size;
-  long long pos = m_start;
-
-  long cue_points_size = 0;
-
-  while (pos < stop) {
-    const long long idpos = pos;
-
-    long len;
-
-    const long long id = ReadID(pReader, pos, len);
-    if (id < 0 || (pos + len) > stop) {
-      return false;
-    }
-
-    pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos, len);
-    if (size < 0 || (pos + len > stop)) {
-      return false;
-    }
-
-    pos += len;  // consume Size field
-    if (pos + size > stop) {
-      return false;
-    }
-
-    if (id == mkvmuxer::kMkvCuePoint) {
-      if (!PreloadCuePoint(cue_points_size, idpos))
-        return false;
-    }
-
-    pos += size;  // skip payload
-  }
-  return true;
-}
-
-bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
-  if (m_count != 0)
-    return false;
-
-  if (m_preload_count >= cue_points_size) {
-    const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
-
-    CuePoint** const qq = new (std::nothrow) CuePoint*[n];
-    if (qq == NULL)
-      return false;
-
-    CuePoint** q = qq;  // beginning of target
-
-    CuePoint** p = m_cue_points;  // beginning of source
-    CuePoint** const pp = p + m_preload_count;  // end of source
-
-    while (p != pp)
-      *q++ = *p++;
-
-    delete[] m_cue_points;
-
-    m_cue_points = qq;
-    cue_points_size = n;
-  }
-
-  CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
-  if (pCP == NULL)
-    return false;
-
-  m_cue_points[m_preload_count++] = pCP;
-  return true;
-}
-
-bool Cues::LoadCuePoint() const {
-  const long long stop = m_start + m_size;
-
-  if (m_pos >= stop)
-    return false;  // nothing else to do
-
-  if (!Init()) {
-    m_pos = stop;
-    return false;
-  }
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  while (m_pos < stop) {
-    const long long idpos = m_pos;
-
-    long len;
-
-    const long long id = ReadID(pReader, m_pos, len);
-    if (id < 0 || (m_pos + len) > stop)
-      return false;
-
-    m_pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, m_pos, len);
-    if (size < 0 || (m_pos + len) > stop)
-      return false;
-
-    m_pos += len;  // consume Size field
-    if ((m_pos + size) > stop)
-      return false;
-
-    if (id != mkvmuxer::kMkvCuePoint) {
-      m_pos += size;  // consume payload
-      if (m_pos > stop)
-        return false;
-
-      continue;
-    }
-
-    if (m_preload_count < 1)
-      return false;
-
-    CuePoint* const pCP = m_cue_points[m_count];
-    if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
-      return false;
-
-    if (!pCP->Load(pReader)) {
-      m_pos = stop;
-      return false;
-    }
-    ++m_count;
-    --m_preload_count;
-
-    m_pos += size;  // consume payload
-    if (m_pos > stop)
-      return false;
-
-    return true;  // yes, we loaded a cue point
-  }
-
-  return false;  // no, we did not load a cue point
-}
-
-bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
-                const CuePoint::TrackPosition*& pTP) const {
-  if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
-    return false;
-
-  CuePoint** const ii = m_cue_points;
-  CuePoint** i = ii;
-
-  CuePoint** const jj = ii + m_count;
-  CuePoint** j = jj;
-
-  pCP = *i;
-  if (pCP == NULL)
-    return false;
-
-  if (time_ns <= pCP->GetTime(m_pSegment)) {
-    pTP = pCP->Find(pTrack);
-    return (pTP != NULL);
-  }
-
-  while (i < j) {
-    // INVARIANT:
-    //[ii, i) <= time_ns
-    //[i, j)  ?
-    //[j, jj) > time_ns
-
-    CuePoint** const k = i + (j - i) / 2;
-    if (k >= jj)
-      return false;
-
-    CuePoint* const pCP = *k;
-    if (pCP == NULL)
-      return false;
-
-    const long long t = pCP->GetTime(m_pSegment);
-
-    if (t <= time_ns)
-      i = k + 1;
-    else
-      j = k;
-
-    if (i > j)
-      return false;
-  }
-
-  if (i != j || i > jj || i <= ii)
-    return false;
-
-  pCP = *--i;
-
-  if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
-    return false;
-
-  // TODO: here and elsewhere, it's probably not correct to search
-  // for the cue point with this time, and then search for a matching
-  // track.  In principle, the matching track could be on some earlier
-  // cue point, and with our current algorithm, we'd miss it.  To make
-  // this bullet-proof, we'd need to create a secondary structure,
-  // with a list of cue points that apply to a track, and then search
-  // that track-based structure for a matching cue point.
-
-  pTP = pCP->Find(pTrack);
-  return (pTP != NULL);
-}
-
-const CuePoint* Cues::GetFirst() const {
-  if (m_cue_points == NULL || m_count == 0)
-    return NULL;
-
-  CuePoint* const* const pp = m_cue_points;
-  if (pp == NULL)
-    return NULL;
-
-  CuePoint* const pCP = pp[0];
-  if (pCP == NULL || pCP->GetTimeCode() < 0)
-    return NULL;
-
-  return pCP;
-}
-
-const CuePoint* Cues::GetLast() const {
-  if (m_cue_points == NULL || m_count <= 0)
-    return NULL;
-
-  const long index = m_count - 1;
-
-  CuePoint* const* const pp = m_cue_points;
-  if (pp == NULL)
-    return NULL;
-
-  CuePoint* const pCP = pp[index];
-  if (pCP == NULL || pCP->GetTimeCode() < 0)
-    return NULL;
-
-  return pCP;
-}
-
-const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
-  if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
-      m_cue_points == NULL || m_count < 1) {
-    return NULL;
-  }
-
-  long index = pCurr->m_index;
-  if (index >= m_count)
-    return NULL;
-
-  CuePoint* const* const pp = m_cue_points;
-  if (pp == NULL || pp[index] != pCurr)
-    return NULL;
-
-  ++index;
-
-  if (index >= m_count)
-    return NULL;
-
-  CuePoint* const pNext = pp[index];
-
-  if (pNext == NULL || pNext->GetTimeCode() < 0)
-    return NULL;
-
-  return pNext;
-}
-
-const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
-                                 const CuePoint::TrackPosition* pTP) const {
-  if (pCP == NULL || pTP == NULL)
-    return NULL;
-
-  return m_pSegment->GetBlock(*pCP, *pTP);
-}
-
-const BlockEntry* Segment::GetBlock(const CuePoint& cp,
-                                    const CuePoint::TrackPosition& tp) {
-  Cluster** const ii = m_clusters;
-  Cluster** i = ii;
-
-  const long count = m_clusterCount + m_clusterPreloadCount;
-
-  Cluster** const jj = ii + count;
-  Cluster** j = jj;
-
-  while (i < j) {
-    // INVARIANT:
-    //[ii, i) < pTP->m_pos
-    //[i, j) ?
-    //[j, jj)  > pTP->m_pos
-
-    Cluster** const k = i + (j - i) / 2;
-    assert(k < jj);
-
-    Cluster* const pCluster = *k;
-    assert(pCluster);
-
-    // const long long pos_ = pCluster->m_pos;
-    // assert(pos_);
-    // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
-
-    const long long pos = pCluster->GetPosition();
-    assert(pos >= 0);
-
-    if (pos < tp.m_pos)
-      i = k + 1;
-    else if (pos > tp.m_pos)
-      j = k;
-    else
-      return pCluster->GetEntry(cp, tp);
-  }
-
-  assert(i == j);
-  // assert(Cluster::HasBlockEntries(this, tp.m_pos));
-
-  Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos);  //, -1);
-  if (pCluster == NULL)
-    return NULL;
-
-  const ptrdiff_t idx = i - m_clusters;
-
-  if (!PreloadCluster(pCluster, idx)) {
-    delete pCluster;
-    return NULL;
-  }
-  assert(m_clusters);
-  assert(m_clusterPreloadCount > 0);
-  assert(m_clusters[idx] == pCluster);
-
-  return pCluster->GetEntry(cp, tp);
-}
-
-const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
-  if (requested_pos < 0)
-    return 0;
-
-  Cluster** const ii = m_clusters;
-  Cluster** i = ii;
-
-  const long count = m_clusterCount + m_clusterPreloadCount;
-
-  Cluster** const jj = ii + count;
-  Cluster** j = jj;
-
-  while (i < j) {
-    // INVARIANT:
-    //[ii, i) < pTP->m_pos
-    //[i, j) ?
-    //[j, jj)  > pTP->m_pos
-
-    Cluster** const k = i + (j - i) / 2;
-    assert(k < jj);
-
-    Cluster* const pCluster = *k;
-    assert(pCluster);
-
-    // const long long pos_ = pCluster->m_pos;
-    // assert(pos_);
-    // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
-
-    const long long pos = pCluster->GetPosition();
-    assert(pos >= 0);
-
-    if (pos < requested_pos)
-      i = k + 1;
-    else if (pos > requested_pos)
-      j = k;
-    else
-      return pCluster;
-  }
-
-  assert(i == j);
-  // assert(Cluster::HasBlockEntries(this, tp.m_pos));
-
-  Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
-  if (pCluster == NULL)
-    return NULL;
-
-  const ptrdiff_t idx = i - m_clusters;
-
-  if (!PreloadCluster(pCluster, idx)) {
-    delete pCluster;
-    return NULL;
-  }
-  assert(m_clusters);
-  assert(m_clusterPreloadCount > 0);
-  assert(m_clusters[idx] == pCluster);
-
-  return pCluster;
-}
-
-CuePoint::CuePoint(long idx, long long pos)
-    : m_element_start(0),
-      m_element_size(0),
-      m_index(idx),
-      m_timecode(-1 * pos),
-      m_track_positions(NULL),
-      m_track_positions_count(0) {
-  assert(pos > 0);
-}
-
-CuePoint::~CuePoint() { delete[] m_track_positions; }
-
-bool CuePoint::Load(IMkvReader* pReader) {
-  // odbgstream os;
-  // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
-
-  if (m_timecode >= 0)  // already loaded
-    return true;
-
-  assert(m_track_positions == NULL);
-  assert(m_track_positions_count == 0);
-
-  long long pos_ = -m_timecode;
-  const long long element_start = pos_;
-
-  long long stop;
-
-  {
-    long len;
-
-    const long long id = ReadID(pReader, pos_, len);
-    if (id != mkvmuxer::kMkvCuePoint)
-      return false;
-
-    pos_ += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos_, len);
-    assert(size >= 0);
-
-    pos_ += len;  // consume Size field
-    // pos_ now points to start of payload
-
-    stop = pos_ + size;
-  }
-
-  const long long element_size = stop - element_start;
-
-  long long pos = pos_;
-
-  // First count number of track positions
-
-  while (pos < stop) {
-    long len;
-
-    const long long id = ReadID(pReader, pos, len);
-    if ((id < 0) || (pos + len > stop)) {
-      return false;
-    }
-
-    pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos, len);
-    if ((size < 0) || (pos + len > stop)) {
-      return false;
-    }
-
-    pos += len;  // consume Size field
-    if ((pos + size) > stop) {
-      return false;
-    }
-
-    if (id == mkvmuxer::kMkvCueTime)
-      m_timecode = UnserializeUInt(pReader, pos, size);
-
-    else if (id == mkvmuxer::kMkvCueTrackPositions)
-      ++m_track_positions_count;
-
-    pos += size;  // consume payload
-  }
-
-  if (m_timecode < 0 || m_track_positions_count <= 0) {
-    return false;
-  }
-
-  // os << "CuePoint::Load(cont'd): idpos=" << idpos
-  //   << " timecode=" << m_timecode
-  //   << endl;
-
-  m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
-  if (m_track_positions == NULL)
-    return false;
-
-  // Now parse track positions
-
-  TrackPosition* p = m_track_positions;
-  pos = pos_;
-
-  while (pos < stop) {
-    long len;
-
-    const long long id = ReadID(pReader, pos, len);
-    if (id < 0 || (pos + len) > stop)
-      return false;
-
-    pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos, len);
-    assert(size >= 0);
-    assert((pos + len) <= stop);
-
-    pos += len;  // consume Size field
-    assert((pos + size) <= stop);
-
-    if (id == mkvmuxer::kMkvCueTrackPositions) {
-      TrackPosition& tp = *p++;
-      if (!tp.Parse(pReader, pos, size)) {
-        return false;
-      }
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return false;
-  }
-
-  assert(size_t(p - m_track_positions) == m_track_positions_count);
-
-  m_element_start = element_start;
-  m_element_size = element_size;
-
-  return true;
-}
-
-bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
-                                    long long size_) {
-  const long long stop = start_ + size_;
-  long long pos = start_;
-
-  m_track = -1;
-  m_pos = -1;
-  m_block = 1;  // default
-
-  while (pos < stop) {
-    long len;
-
-    const long long id = ReadID(pReader, pos, len);
-    if ((id < 0) || ((pos + len) > stop)) {
-      return false;
-    }
-
-    pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos, len);
-    if ((size < 0) || ((pos + len) > stop)) {
-      return false;
-    }
-
-    pos += len;  // consume Size field
-    if ((pos + size) > stop) {
-      return false;
-    }
-
-    if (id == mkvmuxer::kMkvCueTrack)
-      m_track = UnserializeUInt(pReader, pos, size);
-    else if (id == mkvmuxer::kMkvCueClusterPosition)
-      m_pos = UnserializeUInt(pReader, pos, size);
-    else if (id == mkvmuxer::kMkvCueBlockNumber)
-      m_block = UnserializeUInt(pReader, pos, size);
-
-    pos += size;  // consume payload
-  }
-
-  if ((m_pos < 0) || (m_track <= 0)) {
-    return false;
-  }
-
-  return true;
-}
-
-const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
-  assert(pTrack);
-
-  const long long n = pTrack->GetNumber();
-
-  const TrackPosition* i = m_track_positions;
-  const TrackPosition* const j = i + m_track_positions_count;
-
-  while (i != j) {
-    const TrackPosition& p = *i++;
-
-    if (p.m_track == n)
-      return &p;
-  }
-
-  return NULL;  // no matching track number found
-}
-
-long long CuePoint::GetTimeCode() const { return m_timecode; }
-
-long long CuePoint::GetTime(const Segment* pSegment) const {
-  assert(pSegment);
-  assert(m_timecode >= 0);
-
-  const SegmentInfo* const pInfo = pSegment->GetInfo();
-  assert(pInfo);
-
-  const long long scale = pInfo->GetTimeCodeScale();
-  assert(scale >= 1);
-
-  const long long time = scale * m_timecode;
-
-  return time;
-}
-
-bool Segment::DoneParsing() const {
-  if (m_size < 0) {
-    long long total, avail;
-
-    const int status = m_pReader->Length(&total, &avail);
-
-    if (status < 0)  // error
-      return true;  // must assume done
-
-    if (total < 0)
-      return false;  // assume live stream
-
-    return (m_pos >= total);
-  }
-
-  const long long stop = m_start + m_size;
-
-  return (m_pos >= stop);
-}
-
-const Cluster* Segment::GetFirst() const {
-  if ((m_clusters == NULL) || (m_clusterCount <= 0))
-    return &m_eos;
-
-  Cluster* const pCluster = m_clusters[0];
-  assert(pCluster);
-
-  return pCluster;
-}
-
-const Cluster* Segment::GetLast() const {
-  if ((m_clusters == NULL) || (m_clusterCount <= 0))
-    return &m_eos;
-
-  const long idx = m_clusterCount - 1;
-
-  Cluster* const pCluster = m_clusters[idx];
-  assert(pCluster);
-
-  return pCluster;
-}
-
-unsigned long Segment::GetCount() const { return m_clusterCount; }
-
-const Cluster* Segment::GetNext(const Cluster* pCurr) {
-  assert(pCurr);
-  assert(pCurr != &m_eos);
-  assert(m_clusters);
-
-  long idx = pCurr->m_index;
-
-  if (idx >= 0) {
-    assert(m_clusterCount > 0);
-    assert(idx < m_clusterCount);
-    assert(pCurr == m_clusters[idx]);
-
-    ++idx;
-
-    if (idx >= m_clusterCount)
-      return &m_eos;  // caller will LoadCluster as desired
-
-    Cluster* const pNext = m_clusters[idx];
-    assert(pNext);
-    assert(pNext->m_index >= 0);
-    assert(pNext->m_index == idx);
-
-    return pNext;
-  }
-
-  assert(m_clusterPreloadCount > 0);
-
-  long long pos = pCurr->m_element_start;
-
-  assert(m_size >= 0);  // TODO
-  const long long stop = m_start + m_size;  // end of segment
-
-  {
-    long len;
-
-    long long result = GetUIntLength(m_pReader, pos, len);
-    assert(result == 0);
-    assert((pos + len) <= stop);  // TODO
-    if (result != 0)
-      return NULL;
-
-    const long long id = ReadID(m_pReader, pos, len);
-    if (id != mkvmuxer::kMkvCluster)
-      return NULL;
-
-    pos += len;  // consume ID
-
-    // Read Size
-    result = GetUIntLength(m_pReader, pos, len);
-    assert(result == 0);  // TODO
-    assert((pos + len) <= stop);  // TODO
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-    assert(size > 0);  // TODO
-    // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
-
-    pos += len;  // consume length of size of element
-    assert((pos + size) <= stop);  // TODO
-
-    // Pos now points to start of payload
-
-    pos += size;  // consume payload
-  }
-
-  long long off_next = 0;
-
-  while (pos < stop) {
-    long len;
-
-    long long result = GetUIntLength(m_pReader, pos, len);
-    assert(result == 0);
-    assert((pos + len) <= stop);  // TODO
-    if (result != 0)
-      return NULL;
-
-    const long long idpos = pos;  // pos of next (potential) cluster
-
-    const long long id = ReadID(m_pReader, idpos, len);
-    if (id < 0)
-      return NULL;
-
-    pos += len;  // consume ID
-
-    // Read Size
-    result = GetUIntLength(m_pReader, pos, len);
-    assert(result == 0);  // TODO
-    assert((pos + len) <= stop);  // TODO
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-    assert(size >= 0);  // TODO
-
-    pos += len;  // consume length of size of element
-    assert((pos + size) <= stop);  // TODO
-
-    // Pos now points to start of payload
-
-    if (size == 0)  // weird
-      continue;
-
-    if (id == mkvmuxer::kMkvCluster) {
-      const long long off_next_ = idpos - m_start;
-
-      long long pos_;
-      long len_;
-
-      const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
-
-      assert(status >= 0);
-
-      if (status > 0) {
-        off_next = off_next_;
-        break;
-      }
-    }
-
-    pos += size;  // consume payload
-  }
-
-  if (off_next <= 0)
-    return 0;
-
-  Cluster** const ii = m_clusters + m_clusterCount;
-  Cluster** i = ii;
-
-  Cluster** const jj = ii + m_clusterPreloadCount;
-  Cluster** j = jj;
-
-  while (i < j) {
-    // INVARIANT:
-    //[0, i) < pos_next
-    //[i, j) ?
-    //[j, jj)  > pos_next
-
-    Cluster** const k = i + (j - i) / 2;
-    assert(k < jj);
-
-    Cluster* const pNext = *k;
-    assert(pNext);
-    assert(pNext->m_index < 0);
-
-    // const long long pos_ = pNext->m_pos;
-    // assert(pos_);
-    // pos = pos_ * ((pos_ < 0) ? -1 : 1);
-
-    pos = pNext->GetPosition();
-
-    if (pos < off_next)
-      i = k + 1;
-    else if (pos > off_next)
-      j = k;
-    else
-      return pNext;
-  }
-
-  assert(i == j);
-
-  Cluster* const pNext = Cluster::Create(this, -1, off_next);
-  if (pNext == NULL)
-    return NULL;
-
-  const ptrdiff_t idx_next = i - m_clusters;  // insertion position
-
-  if (!PreloadCluster(pNext, idx_next)) {
-    delete pNext;
-    return NULL;
-  }
-  assert(m_clusters);
-  assert(idx_next < m_clusterSize);
-  assert(m_clusters[idx_next] == pNext);
-
-  return pNext;
-}
-
-long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
-                        long long& pos, long& len) {
-  assert(pCurr);
-  assert(!pCurr->EOS());
-  assert(m_clusters);
-
-  pResult = 0;
-
-  if (pCurr->m_index >= 0) {  // loaded (not merely preloaded)
-    assert(m_clusters[pCurr->m_index] == pCurr);
-
-    const long next_idx = pCurr->m_index + 1;
-
-    if (next_idx < m_clusterCount) {
-      pResult = m_clusters[next_idx];
-      return 0;  // success
-    }
-
-    // curr cluster is last among loaded
-
-    const long result = LoadCluster(pos, len);
-
-    if (result < 0)  // error or underflow
-      return result;
-
-    if (result > 0)  // no more clusters
-    {
-      // pResult = &m_eos;
-      return 1;
-    }
-
-    pResult = GetLast();
-    return 0;  // success
-  }
-
-  assert(m_pos > 0);
-
-  long long total, avail;
-
-  long status = m_pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
-
-  // interrogate curr cluster
-
-  pos = pCurr->m_element_start;
-
-  if (pCurr->m_element_size >= 0)
-    pos += pCurr->m_element_size;
-  else {
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadUInt(m_pReader, pos, len);
-
-    if (id != mkvmuxer::kMkvCluster)
-      return -1;
-
-    pos += len;  // consume ID
-
-    // Read Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    pos += len;  // consume size field
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size == unknown_size)  // TODO: should never happen
-      return E_FILE_FORMAT_INVALID;  // TODO: resolve this
-
-    // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
-
-    if ((segment_stop >= 0) && ((pos + size) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    // Pos now points to start of payload
-
-    pos += size;  // consume payload (that is, the current cluster)
-    if (segment_stop >= 0 && pos > segment_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    // By consuming the payload, we are assuming that the curr
-    // cluster isn't interesting.  That is, we don't bother checking
-    // whether the payload of the curr cluster is less than what
-    // happens to be available (obtained via IMkvReader::Length).
-    // Presumably the caller has already dispensed with the current
-    // cluster, and really does want the next cluster.
-  }
-
-  // pos now points to just beyond the last fully-loaded cluster
-
-  for (;;) {
-    const long status = DoParseNext(pResult, pos, len);
-
-    if (status <= 1)
-      return status;
-  }
-}
-
-long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
-  long long total, avail;
-
-  long status = m_pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
-
-  // Parse next cluster.  This is strictly a parsing activity.
-  // Creation of a new cluster object happens later, after the
-  // parsing is done.
-
-  long long off_next = 0;
-  long long cluster_size = -1;
-
-  for (;;) {
-    if ((total >= 0) && (pos >= total))
-      return 1;  // EOF
-
-    if ((segment_stop >= 0) && (pos >= segment_stop))
-      return 1;  // EOF
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long idpos = pos;  // absolute
-    const long long idoff = pos - m_start;  // relative
-
-    const long long id = ReadID(m_pReader, idpos, len);  // absolute
-
-    if (id < 0)  // error
-      return static_cast<long>(id);
-
-    if (id == 0)  // weird
-      return -1;  // generic error
-
-    pos += len;  // consume ID
-
-    // Read Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(m_pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(m_pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    pos += len;  // consume length of size of element
-
-    // Pos now points to start of payload
-
-    if (size == 0)  // weird
-      continue;
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if ((segment_stop >= 0) && (size != unknown_size) &&
-        ((pos + size) > segment_stop)) {
-      return E_FILE_FORMAT_INVALID;
-    }
-
-    if (id == mkvmuxer::kMkvCues) {
-      if (size == unknown_size)
-        return E_FILE_FORMAT_INVALID;
-
-      const long long element_stop = pos + size;
-
-      if ((segment_stop >= 0) && (element_stop > segment_stop))
-        return E_FILE_FORMAT_INVALID;
-
-      const long long element_start = idpos;
-      const long long element_size = element_stop - element_start;
-
-      if (m_pCues == NULL) {
-        m_pCues = new (std::nothrow)
-            Cues(this, pos, size, element_start, element_size);
-        if (m_pCues == NULL)
-          return false;
-      }
-
-      pos += size;  // consume payload
-      if (segment_stop >= 0 && pos > segment_stop)
-        return E_FILE_FORMAT_INVALID;
-
-      continue;
-    }
-
-    if (id != mkvmuxer::kMkvCluster) {  // not a Cluster ID
-      if (size == unknown_size)
-        return E_FILE_FORMAT_INVALID;
-
-      pos += size;  // consume payload
-      if (segment_stop >= 0 && pos > segment_stop)
-        return E_FILE_FORMAT_INVALID;
-
-      continue;
-    }
-
-    // We have a cluster.
-    off_next = idoff;
-
-    if (size != unknown_size)
-      cluster_size = size;
-
-    break;
-  }
-
-  assert(off_next > 0);  // have cluster
-
-  // We have parsed the next cluster.
-  // We have not created a cluster object yet.  What we need
-  // to do now is determine whether it has already be preloaded
-  //(in which case, an object for this cluster has already been
-  // created), and if not, create a new cluster object.
-
-  Cluster** const ii = m_clusters + m_clusterCount;
-  Cluster** i = ii;
-
-  Cluster** const jj = ii + m_clusterPreloadCount;
-  Cluster** j = jj;
-
-  while (i < j) {
-    // INVARIANT:
-    //[0, i) < pos_next
-    //[i, j) ?
-    //[j, jj)  > pos_next
-
-    Cluster** const k = i + (j - i) / 2;
-    assert(k < jj);
-
-    const Cluster* const pNext = *k;
-    assert(pNext);
-    assert(pNext->m_index < 0);
-
-    pos = pNext->GetPosition();
-    assert(pos >= 0);
-
-    if (pos < off_next)
-      i = k + 1;
-    else if (pos > off_next)
-      j = k;
-    else {
-      pResult = pNext;
-      return 0;  // success
-    }
-  }
-
-  assert(i == j);
-
-  long long pos_;
-  long len_;
-
-  status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
-
-  if (status < 0) {  // error or underflow
-    pos = pos_;
-    len = len_;
-
-    return status;
-  }
-
-  if (status > 0) {  // means "found at least one block entry"
-    Cluster* const pNext = Cluster::Create(this,
-                                           -1,  // preloaded
-                                           off_next);
-    if (pNext == NULL)
-      return -1;
-
-    const ptrdiff_t idx_next = i - m_clusters;  // insertion position
-
-    if (!PreloadCluster(pNext, idx_next)) {
-      delete pNext;
-      return -1;
-    }
-    assert(m_clusters);
-    assert(idx_next < m_clusterSize);
-    assert(m_clusters[idx_next] == pNext);
-
-    pResult = pNext;
-    return 0;  // success
-  }
-
-  // status == 0 means "no block entries found"
-
-  if (cluster_size < 0) {  // unknown size
-    const long long payload_pos = pos;  // absolute pos of cluster payload
-
-    for (;;) {  // determine cluster size
-      if ((total >= 0) && (pos >= total))
-        break;
-
-      if ((segment_stop >= 0) && (pos >= segment_stop))
-        break;  // no more clusters
-
-      // Read ID
-
-      if ((pos + 1) > avail) {
-        len = 1;
-        return E_BUFFER_NOT_FULL;
-      }
-
-      long long result = GetUIntLength(m_pReader, pos, len);
-
-      if (result < 0)  // error
-        return static_cast<long>(result);
-
-      if (result > 0)  // weird
-        return E_BUFFER_NOT_FULL;
-
-      if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-        return E_FILE_FORMAT_INVALID;
-
-      if ((pos + len) > avail)
-        return E_BUFFER_NOT_FULL;
-
-      const long long idpos = pos;
-      const long long id = ReadID(m_pReader, idpos, len);
-
-      if (id < 0)  // error (or underflow)
-        return static_cast<long>(id);
-
-      // This is the distinguished set of ID's we use to determine
-      // that we have exhausted the sub-element's inside the cluster
-      // whose ID we parsed earlier.
-
-      if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues)
-        break;
-
-      pos += len;  // consume ID (of sub-element)
-
-      // Read Size
-
-      if ((pos + 1) > avail) {
-        len = 1;
-        return E_BUFFER_NOT_FULL;
-      }
-
-      result = GetUIntLength(m_pReader, pos, len);
-
-      if (result < 0)  // error
-        return static_cast<long>(result);
-
-      if (result > 0)  // weird
-        return E_BUFFER_NOT_FULL;
-
-      if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-        return E_FILE_FORMAT_INVALID;
-
-      if ((pos + len) > avail)
-        return E_BUFFER_NOT_FULL;
-
-      const long long size = ReadUInt(m_pReader, pos, len);
-
-      if (size < 0)  // error
-        return static_cast<long>(size);
-
-      pos += len;  // consume size field of element
-
-      // pos now points to start of sub-element's payload
-
-      if (size == 0)  // weird
-        continue;
-
-      const long long unknown_size = (1LL << (7 * len)) - 1;
-
-      if (size == unknown_size)
-        return E_FILE_FORMAT_INVALID;  // not allowed for sub-elements
-
-      if ((segment_stop >= 0) && ((pos + size) > segment_stop))  // weird
-        return E_FILE_FORMAT_INVALID;
-
-      pos += size;  // consume payload of sub-element
-      if (segment_stop >= 0 && pos > segment_stop)
-        return E_FILE_FORMAT_INVALID;
-    }  // determine cluster size
-
-    cluster_size = pos - payload_pos;
-    assert(cluster_size >= 0);  // TODO: handle cluster_size = 0
-
-    pos = payload_pos;  // reset and re-parse original cluster
-  }
-
-  pos += cluster_size;  // consume payload
-  if (segment_stop >= 0 && pos > segment_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 2;  // try to find a cluster that follows next
-}
-
-const Cluster* Segment::FindCluster(long long time_ns) const {
-  if ((m_clusters == NULL) || (m_clusterCount <= 0))
-    return &m_eos;
-
-  {
-    Cluster* const pCluster = m_clusters[0];
-    assert(pCluster);
-    assert(pCluster->m_index == 0);
-
-    if (time_ns <= pCluster->GetTime())
-      return pCluster;
-  }
-
-  // Binary search of cluster array
-
-  long i = 0;
-  long j = m_clusterCount;
-
-  while (i < j) {
-    // INVARIANT:
-    //[0, i) <= time_ns
-    //[i, j) ?
-    //[j, m_clusterCount)  > time_ns
-
-    const long k = i + (j - i) / 2;
-    assert(k < m_clusterCount);
-
-    Cluster* const pCluster = m_clusters[k];
-    assert(pCluster);
-    assert(pCluster->m_index == k);
-
-    const long long t = pCluster->GetTime();
-
-    if (t <= time_ns)
-      i = k + 1;
-    else
-      j = k;
-
-    assert(i <= j);
-  }
-
-  assert(i == j);
-  assert(i > 0);
-  assert(i <= m_clusterCount);
-
-  const long k = i - 1;
-
-  Cluster* const pCluster = m_clusters[k];
-  assert(pCluster);
-  assert(pCluster->m_index == k);
-  assert(pCluster->GetTime() <= time_ns);
-
-  return pCluster;
-}
-
-const Tracks* Segment::GetTracks() const { return m_pTracks; }
-const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
-const Cues* Segment::GetCues() const { return m_pCues; }
-const Chapters* Segment::GetChapters() const { return m_pChapters; }
-const Tags* Segment::GetTags() const { return m_pTags; }
-const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
-
-long long Segment::GetDuration() const {
-  assert(m_pInfo);
-  return m_pInfo->GetDuration();
-}
-
-Chapters::Chapters(Segment* pSegment, long long payload_start,
-                   long long payload_size, long long element_start,
-                   long long element_size)
-    : m_pSegment(pSegment),
-      m_start(payload_start),
-      m_size(payload_size),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_editions(NULL),
-      m_editions_size(0),
-      m_editions_count(0) {}
-
-Chapters::~Chapters() {
-  while (m_editions_count > 0) {
-    Edition& e = m_editions[--m_editions_count];
-    e.Clear();
-  }
-  delete[] m_editions;
-}
-
-long Chapters::Parse() {
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = m_start;  // payload start
-  const long long stop = pos + m_size;  // payload stop
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)  // weird
-      continue;
-
-    if (id == mkvmuxer::kMkvEditionEntry) {
-      status = ParseEdition(pos, size);
-
-      if (status < 0)  // error
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-int Chapters::GetEditionCount() const { return m_editions_count; }
-
-const Chapters::Edition* Chapters::GetEdition(int idx) const {
-  if (idx < 0)
-    return NULL;
-
-  if (idx >= m_editions_count)
-    return NULL;
-
-  return m_editions + idx;
-}
-
-bool Chapters::ExpandEditionsArray() {
-  if (m_editions_size > m_editions_count)
-    return true;  // nothing else to do
-
-  const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
-
-  Edition* const editions = new (std::nothrow) Edition[size];
-
-  if (editions == NULL)
-    return false;
-
-  for (int idx = 0; idx < m_editions_count; ++idx) {
-    m_editions[idx].ShallowCopy(editions[idx]);
-  }
-
-  delete[] m_editions;
-  m_editions = editions;
-
-  m_editions_size = size;
-  return true;
-}
-
-long Chapters::ParseEdition(long long pos, long long size) {
-  if (!ExpandEditionsArray())
-    return -1;
-
-  Edition& e = m_editions[m_editions_count++];
-  e.Init();
-
-  return e.Parse(m_pSegment->m_pReader, pos, size);
-}
-
-Chapters::Edition::Edition() {}
-
-Chapters::Edition::~Edition() {}
-
-int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
-
-const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
-  if (index < 0)
-    return NULL;
-
-  if (index >= m_atoms_count)
-    return NULL;
-
-  return m_atoms + index;
-}
-
-void Chapters::Edition::Init() {
-  m_atoms = NULL;
-  m_atoms_size = 0;
-  m_atoms_count = 0;
-}
-
-void Chapters::Edition::ShallowCopy(Edition& rhs) const {
-  rhs.m_atoms = m_atoms;
-  rhs.m_atoms_size = m_atoms_size;
-  rhs.m_atoms_count = m_atoms_count;
-}
-
-void Chapters::Edition::Clear() {
-  while (m_atoms_count > 0) {
-    Atom& a = m_atoms[--m_atoms_count];
-    a.Clear();
-  }
-
-  delete[] m_atoms;
-  m_atoms = NULL;
-
-  m_atoms_size = 0;
-}
-
-long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
-                              long long size) {
-  const long long stop = pos + size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)
-      continue;
-
-    if (id == mkvmuxer::kMkvChapterAtom) {
-      status = ParseAtom(pReader, pos, size);
-
-      if (status < 0)  // error
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
-                                  long long size) {
-  if (!ExpandAtomsArray())
-    return -1;
-
-  Atom& a = m_atoms[m_atoms_count++];
-  a.Init();
-
-  return a.Parse(pReader, pos, size);
-}
-
-bool Chapters::Edition::ExpandAtomsArray() {
-  if (m_atoms_size > m_atoms_count)
-    return true;  // nothing else to do
-
-  const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
-
-  Atom* const atoms = new (std::nothrow) Atom[size];
-
-  if (atoms == NULL)
-    return false;
-
-  for (int idx = 0; idx < m_atoms_count; ++idx) {
-    m_atoms[idx].ShallowCopy(atoms[idx]);
-  }
-
-  delete[] m_atoms;
-  m_atoms = atoms;
-
-  m_atoms_size = size;
-  return true;
-}
-
-Chapters::Atom::Atom() {}
-
-Chapters::Atom::~Atom() {}
-
-unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
-
-const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
-
-long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
-
-long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
-
-long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
-  return GetTime(pChapters, m_start_timecode);
-}
-
-long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
-  return GetTime(pChapters, m_stop_timecode);
-}
-
-int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
-
-const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
-  if (index < 0)
-    return NULL;
-
-  if (index >= m_displays_count)
-    return NULL;
-
-  return m_displays + index;
-}
-
-void Chapters::Atom::Init() {
-  m_string_uid = NULL;
-  m_uid = 0;
-  m_start_timecode = -1;
-  m_stop_timecode = -1;
-
-  m_displays = NULL;
-  m_displays_size = 0;
-  m_displays_count = 0;
-}
-
-void Chapters::Atom::ShallowCopy(Atom& rhs) const {
-  rhs.m_string_uid = m_string_uid;
-  rhs.m_uid = m_uid;
-  rhs.m_start_timecode = m_start_timecode;
-  rhs.m_stop_timecode = m_stop_timecode;
-
-  rhs.m_displays = m_displays;
-  rhs.m_displays_size = m_displays_size;
-  rhs.m_displays_count = m_displays_count;
-}
-
-void Chapters::Atom::Clear() {
-  delete[] m_string_uid;
-  m_string_uid = NULL;
-
-  while (m_displays_count > 0) {
-    Display& d = m_displays[--m_displays_count];
-    d.Clear();
-  }
-
-  delete[] m_displays;
-  m_displays = NULL;
-
-  m_displays_size = 0;
-}
-
-long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
-  const long long stop = pos + size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)  // 0 length payload, skip.
-      continue;
-
-    if (id == mkvmuxer::kMkvChapterDisplay) {
-      status = ParseDisplay(pReader, pos, size);
-
-      if (status < 0)  // error
-        return status;
-    } else if (id == mkvmuxer::kMkvChapterStringUID) {
-      status = UnserializeString(pReader, pos, size, m_string_uid);
-
-      if (status < 0)  // error
-        return status;
-    } else if (id == mkvmuxer::kMkvChapterUID) {
-      long long val;
-      status = UnserializeInt(pReader, pos, size, val);
-
-      if (status < 0)  // error
-        return status;
-
-      m_uid = static_cast<unsigned long long>(val);
-    } else if (id == mkvmuxer::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) {
-      const long long val = UnserializeUInt(pReader, pos, size);
-
-      if (val < 0)  // error
-        return static_cast<long>(val);
-
-      m_stop_timecode = val;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-long long Chapters::Atom::GetTime(const Chapters* pChapters,
-                                  long long timecode) {
-  if (pChapters == NULL)
-    return -1;
-
-  Segment* const pSegment = pChapters->m_pSegment;
-
-  if (pSegment == NULL)  // weird
-    return -1;
-
-  const SegmentInfo* const pInfo = pSegment->GetInfo();
-
-  if (pInfo == NULL)
-    return -1;
-
-  const long long timecode_scale = pInfo->GetTimeCodeScale();
-
-  if (timecode_scale < 1)  // weird
-    return -1;
-
-  if (timecode < 0)
-    return -1;
-
-  const long long result = timecode_scale * timecode;
-
-  return result;
-}
-
-long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
-                                  long long size) {
-  if (!ExpandDisplaysArray())
-    return -1;
-
-  Display& d = m_displays[m_displays_count++];
-  d.Init();
-
-  return d.Parse(pReader, pos, size);
-}
-
-bool Chapters::Atom::ExpandDisplaysArray() {
-  if (m_displays_size > m_displays_count)
-    return true;  // nothing else to do
-
-  const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
-
-  Display* const displays = new (std::nothrow) Display[size];
-
-  if (displays == NULL)
-    return false;
-
-  for (int idx = 0; idx < m_displays_count; ++idx) {
-    m_displays[idx].ShallowCopy(displays[idx]);
-  }
-
-  delete[] m_displays;
-  m_displays = displays;
-
-  m_displays_size = size;
-  return true;
-}
-
-Chapters::Display::Display() {}
-
-Chapters::Display::~Display() {}
-
-const char* Chapters::Display::GetString() const { return m_string; }
-
-const char* Chapters::Display::GetLanguage() const { return m_language; }
-
-const char* Chapters::Display::GetCountry() const { return m_country; }
-
-void Chapters::Display::Init() {
-  m_string = NULL;
-  m_language = NULL;
-  m_country = NULL;
-}
-
-void Chapters::Display::ShallowCopy(Display& rhs) const {
-  rhs.m_string = m_string;
-  rhs.m_language = m_language;
-  rhs.m_country = m_country;
-}
-
-void Chapters::Display::Clear() {
-  delete[] m_string;
-  m_string = NULL;
-
-  delete[] m_language;
-  m_language = NULL;
-
-  delete[] m_country;
-  m_country = NULL;
-}
-
-long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
-                              long long size) {
-  const long long stop = pos + size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)  // No payload.
-      continue;
-
-    if (id == mkvmuxer::kMkvChapString) {
-      status = UnserializeString(pReader, pos, size, m_string);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvChapLanguage) {
-      status = UnserializeString(pReader, pos, size, m_language);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvChapCountry) {
-      status = UnserializeString(pReader, pos, size, m_country);
-
-      if (status)
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
-           long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_start(payload_start),
-      m_size(payload_size),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_tags(NULL),
-      m_tags_size(0),
-      m_tags_count(0) {}
-
-Tags::~Tags() {
-  while (m_tags_count > 0) {
-    Tag& t = m_tags[--m_tags_count];
-    t.Clear();
-  }
-  delete[] m_tags;
-}
-
-long Tags::Parse() {
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = m_start;  // payload start
-  const long long stop = pos + m_size;  // payload stop
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)
-      return status;
-
-    if (size == 0)  // 0 length tag, read another
-      continue;
-
-    if (id == mkvmuxer::kMkvTag) {
-      status = ParseTag(pos, size);
-
-      if (status < 0)
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-int Tags::GetTagCount() const { return m_tags_count; }
-
-const Tags::Tag* Tags::GetTag(int idx) const {
-  if (idx < 0)
-    return NULL;
-
-  if (idx >= m_tags_count)
-    return NULL;
-
-  return m_tags + idx;
-}
-
-bool Tags::ExpandTagsArray() {
-  if (m_tags_size > m_tags_count)
-    return true;  // nothing else to do
-
-  const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
-
-  Tag* const tags = new (std::nothrow) Tag[size];
-
-  if (tags == NULL)
-    return false;
-
-  for (int idx = 0; idx < m_tags_count; ++idx) {
-    m_tags[idx].ShallowCopy(tags[idx]);
-  }
-
-  delete[] m_tags;
-  m_tags = tags;
-
-  m_tags_size = size;
-  return true;
-}
-
-long Tags::ParseTag(long long pos, long long size) {
-  if (!ExpandTagsArray())
-    return -1;
-
-  Tag& t = m_tags[m_tags_count++];
-  t.Init();
-
-  return t.Parse(m_pSegment->m_pReader, pos, size);
-}
-
-Tags::Tag::Tag() {}
-
-Tags::Tag::~Tag() {}
-
-int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
-
-const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
-  if (index < 0)
-    return NULL;
-
-  if (index >= m_simple_tags_count)
-    return NULL;
-
-  return m_simple_tags + index;
-}
-
-void Tags::Tag::Init() {
-  m_simple_tags = NULL;
-  m_simple_tags_size = 0;
-  m_simple_tags_count = 0;
-}
-
-void Tags::Tag::ShallowCopy(Tag& rhs) const {
-  rhs.m_simple_tags = m_simple_tags;
-  rhs.m_simple_tags_size = m_simple_tags_size;
-  rhs.m_simple_tags_count = m_simple_tags_count;
-}
-
-void Tags::Tag::Clear() {
-  while (m_simple_tags_count > 0) {
-    SimpleTag& d = m_simple_tags[--m_simple_tags_count];
-    d.Clear();
-  }
-
-  delete[] m_simple_tags;
-  m_simple_tags = NULL;
-
-  m_simple_tags_size = 0;
-}
-
-long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
-  const long long stop = pos + size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)
-      return status;
-
-    if (size == 0)  // 0 length tag, read another
-      continue;
-
-    if (id == mkvmuxer::kMkvSimpleTag) {
-      status = ParseSimpleTag(pReader, pos, size);
-
-      if (status < 0)
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
-                               long long size) {
-  if (!ExpandSimpleTagsArray())
-    return -1;
-
-  SimpleTag& st = m_simple_tags[m_simple_tags_count++];
-  st.Init();
-
-  return st.Parse(pReader, pos, size);
-}
-
-bool Tags::Tag::ExpandSimpleTagsArray() {
-  if (m_simple_tags_size > m_simple_tags_count)
-    return true;  // nothing else to do
-
-  const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
-
-  SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
-
-  if (displays == NULL)
-    return false;
-
-  for (int idx = 0; idx < m_simple_tags_count; ++idx) {
-    m_simple_tags[idx].ShallowCopy(displays[idx]);
-  }
-
-  delete[] m_simple_tags;
-  m_simple_tags = displays;
-
-  m_simple_tags_size = size;
-  return true;
-}
-
-Tags::SimpleTag::SimpleTag() {}
-
-Tags::SimpleTag::~SimpleTag() {}
-
-const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
-
-const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
-
-void Tags::SimpleTag::Init() {
-  m_tag_name = NULL;
-  m_tag_string = NULL;
-}
-
-void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
-  rhs.m_tag_name = m_tag_name;
-  rhs.m_tag_string = m_tag_string;
-}
-
-void Tags::SimpleTag::Clear() {
-  delete[] m_tag_name;
-  m_tag_name = NULL;
-
-  delete[] m_tag_string;
-  m_tag_string = NULL;
-}
-
-long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
-                            long long size) {
-  const long long stop = pos + size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)  // weird
-      continue;
-
-    if (id == mkvmuxer::kMkvTagName) {
-      status = UnserializeString(pReader, pos, size, m_tag_name);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvTagString) {
-      status = UnserializeString(pReader, pos, size, m_tag_string);
-
-      if (status)
-        return status;
-    }
-
-    pos += size;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
-                         long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_start(start),
-      m_size(size_),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_pMuxingAppAsUTF8(NULL),
-      m_pWritingAppAsUTF8(NULL),
-      m_pTitleAsUTF8(NULL) {}
-
-SegmentInfo::~SegmentInfo() {
-  delete[] m_pMuxingAppAsUTF8;
-  m_pMuxingAppAsUTF8 = NULL;
-
-  delete[] m_pWritingAppAsUTF8;
-  m_pWritingAppAsUTF8 = NULL;
-
-  delete[] m_pTitleAsUTF8;
-  m_pTitleAsUTF8 = NULL;
-}
-
-long SegmentInfo::Parse() {
-  assert(m_pMuxingAppAsUTF8 == NULL);
-  assert(m_pWritingAppAsUTF8 == NULL);
-  assert(m_pTitleAsUTF8 == NULL);
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = m_start;
-  const long long stop = m_start + m_size;
-
-  m_timecodeScale = 1000000;
-  m_duration = -1;
-
-  while (pos < stop) {
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvTimecodeScale) {
-      m_timecodeScale = UnserializeUInt(pReader, pos, size);
-
-      if (m_timecodeScale <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDuration) {
-      const long status = UnserializeFloat(pReader, pos, size, m_duration);
-
-      if (status < 0)
-        return status;
-
-      if (m_duration < 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvMuxingApp) {
-      const long status =
-          UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvWritingApp) {
-      const long status =
-          UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvTitle) {
-      const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
-
-      if (status)
-        return status;
-    }
-
-    pos += size;
-
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  const double rollover_check = m_duration * m_timecodeScale;
-  if (rollover_check > LLONG_MAX)
-    return E_FILE_FORMAT_INVALID;
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
-
-long long SegmentInfo::GetDuration() const {
-  if (m_duration < 0)
-    return -1;
-
-  assert(m_timecodeScale >= 1);
-
-  const double dd = double(m_duration) * double(m_timecodeScale);
-  const long long d = static_cast<long long>(dd);
-
-  return d;
-}
-
-const char* SegmentInfo::GetMuxingAppAsUTF8() const {
-  return m_pMuxingAppAsUTF8;
-}
-
-const char* SegmentInfo::GetWritingAppAsUTF8() const {
-  return m_pWritingAppAsUTF8;
-}
-
-const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
-
-///////////////////////////////////////////////////////////////
-// ContentEncoding element
-ContentEncoding::ContentCompression::ContentCompression()
-    : algo(0), settings(NULL), settings_len(0) {}
-
-ContentEncoding::ContentCompression::~ContentCompression() {
-  delete[] settings;
-}
-
-ContentEncoding::ContentEncryption::ContentEncryption()
-    : algo(0),
-      key_id(NULL),
-      key_id_len(0),
-      signature(NULL),
-      signature_len(0),
-      sig_key_id(NULL),
-      sig_key_id_len(0),
-      sig_algo(0),
-      sig_hash_algo(0) {}
-
-ContentEncoding::ContentEncryption::~ContentEncryption() {
-  delete[] key_id;
-  delete[] signature;
-  delete[] sig_key_id;
-}
-
-ContentEncoding::ContentEncoding()
-    : compression_entries_(NULL),
-      compression_entries_end_(NULL),
-      encryption_entries_(NULL),
-      encryption_entries_end_(NULL),
-      encoding_order_(0),
-      encoding_scope_(1),
-      encoding_type_(0) {}
-
-ContentEncoding::~ContentEncoding() {
-  ContentCompression** comp_i = compression_entries_;
-  ContentCompression** const comp_j = compression_entries_end_;
-
-  while (comp_i != comp_j) {
-    ContentCompression* const comp = *comp_i++;
-    delete comp;
-  }
-
-  delete[] compression_entries_;
-
-  ContentEncryption** enc_i = encryption_entries_;
-  ContentEncryption** const enc_j = encryption_entries_end_;
-
-  while (enc_i != enc_j) {
-    ContentEncryption* const enc = *enc_i++;
-    delete enc;
-  }
-
-  delete[] encryption_entries_;
-}
-
-const ContentEncoding::ContentCompression*
-    ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
-  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
-  assert(count >= 0);
-
-  if (idx >= static_cast<unsigned long>(count))
-    return NULL;
-
-  return compression_entries_[idx];
-}
-
-unsigned long ContentEncoding::GetCompressionCount() const {
-  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
-  assert(count >= 0);
-
-  return static_cast<unsigned long>(count);
-}
-
-const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
-    unsigned long idx) const {
-  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
-  assert(count >= 0);
-
-  if (idx >= static_cast<unsigned long>(count))
-    return NULL;
-
-  return encryption_entries_[idx];
-}
-
-unsigned long ContentEncoding::GetEncryptionCount() const {
-  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
-  assert(count >= 0);
-
-  return static_cast<unsigned long>(count);
-}
-
-long ContentEncoding::ParseContentEncAESSettingsEntry(
-    long long start, long long size, IMkvReader* pReader,
-    ContentEncAESSettings* aes) {
-  assert(pReader);
-  assert(aes);
-
-  long long pos = start;
-  const long long stop = start + size;
-
-  while (pos < stop) {
-    long long id, size;
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvAESSettingsCipherMode) {
-      aes->cipher_mode = UnserializeUInt(pReader, pos, size);
-      if (aes->cipher_mode != 1)
-        return E_FILE_FORMAT_INVALID;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  return 0;
-}
-
-long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
-                                                IMkvReader* pReader) {
-  assert(pReader);
-
-  long long pos = start;
-  const long long stop = start + size;
-
-  // Count ContentCompression and ContentEncryption elements.
-  int compression_count = 0;
-  int encryption_count = 0;
-
-  while (pos < stop) {
-    long long id, size;
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvContentCompression)
-      ++compression_count;
-
-    if (id == mkvmuxer::kMkvContentEncryption)
-      ++encryption_count;
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (compression_count <= 0 && encryption_count <= 0)
-    return -1;
-
-  if (compression_count > 0) {
-    compression_entries_ =
-        new (std::nothrow) ContentCompression*[compression_count];
-    if (!compression_entries_)
-      return -1;
-    compression_entries_end_ = compression_entries_;
-  }
-
-  if (encryption_count > 0) {
-    encryption_entries_ =
-        new (std::nothrow) ContentEncryption*[encryption_count];
-    if (!encryption_entries_) {
-      delete[] compression_entries_;
-      return -1;
-    }
-    encryption_entries_end_ = encryption_entries_;
-  }
-
-  pos = start;
-  while (pos < stop) {
-    long long id, size;
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvContentEncodingOrder) {
-      encoding_order_ = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentEncodingScope) {
-      encoding_scope_ = UnserializeUInt(pReader, pos, size);
-      if (encoding_scope_ < 1)
-        return -1;
-    } else if (id == mkvmuxer::kMkvContentEncodingType) {
-      encoding_type_ = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentCompression) {
-      ContentCompression* const compression =
-          new (std::nothrow) ContentCompression();
-      if (!compression)
-        return -1;
-
-      status = ParseCompressionEntry(pos, size, pReader, compression);
-      if (status) {
-        delete compression;
-        return status;
-      }
-      *compression_entries_end_++ = compression;
-    } else if (id == mkvmuxer::kMkvContentEncryption) {
-      ContentEncryption* const encryption =
-          new (std::nothrow) ContentEncryption();
-      if (!encryption)
-        return -1;
-
-      status = ParseEncryptionEntry(pos, size, pReader, encryption);
-      if (status) {
-        delete encryption;
-        return status;
-      }
-      *encryption_entries_end_++ = encryption;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  return 0;
-}
-
-long ContentEncoding::ParseCompressionEntry(long long start, long long size,
-                                            IMkvReader* pReader,
-                                            ContentCompression* compression) {
-  assert(pReader);
-  assert(compression);
-
-  long long pos = start;
-  const long long stop = start + size;
-
-  bool valid = false;
-
-  while (pos < stop) {
-    long long id, size;
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::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) {
-      if (size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      const size_t buflen = static_cast<size_t>(size);
-      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
-      if (buf == NULL)
-        return -1;
-
-      const int read_status =
-          pReader->Read(pos, static_cast<long>(buflen), buf);
-      if (read_status) {
-        delete[] buf;
-        return status;
-      }
-
-      compression->settings = buf;
-      compression->settings_len = buflen;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  // ContentCompAlgo is mandatory
-  if (!valid)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
-                                           IMkvReader* pReader,
-                                           ContentEncryption* encryption) {
-  assert(pReader);
-  assert(encryption);
-
-  long long pos = start;
-  const long long stop = start + size;
-
-  while (pos < stop) {
-    long long id, size;
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvContentEncAlgo) {
-      encryption->algo = UnserializeUInt(pReader, pos, size);
-      if (encryption->algo != 5)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvContentEncKeyID) {
-      delete[] encryption->key_id;
-      encryption->key_id = NULL;
-      encryption->key_id_len = 0;
-
-      if (size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      const size_t buflen = static_cast<size_t>(size);
-      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
-      if (buf == NULL)
-        return -1;
-
-      const int read_status =
-          pReader->Read(pos, static_cast<long>(buflen), buf);
-      if (read_status) {
-        delete[] buf;
-        return status;
-      }
-
-      encryption->key_id = buf;
-      encryption->key_id_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSignature) {
-      delete[] encryption->signature;
-      encryption->signature = NULL;
-      encryption->signature_len = 0;
-
-      if (size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      const size_t buflen = static_cast<size_t>(size);
-      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
-      if (buf == NULL)
-        return -1;
-
-      const int read_status =
-          pReader->Read(pos, static_cast<long>(buflen), buf);
-      if (read_status) {
-        delete[] buf;
-        return status;
-      }
-
-      encryption->signature = buf;
-      encryption->signature_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSigKeyID) {
-      delete[] encryption->sig_key_id;
-      encryption->sig_key_id = NULL;
-      encryption->sig_key_id_len = 0;
-
-      if (size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      const size_t buflen = static_cast<size_t>(size);
-      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
-      if (buf == NULL)
-        return -1;
-
-      const int read_status =
-          pReader->Read(pos, static_cast<long>(buflen), buf);
-      if (read_status) {
-        delete[] buf;
-        return status;
-      }
-
-      encryption->sig_key_id = buf;
-      encryption->sig_key_id_len = buflen;
-    } else if (id == mkvmuxer::kMkvContentSigAlgo) {
-      encryption->sig_algo = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentSigHashAlgo) {
-      encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvContentEncAESSettings) {
-      const long status = ParseContentEncAESSettingsEntry(
-          pos, size, pReader, &encryption->aes_settings);
-      if (status)
-        return status;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  return 0;
-}
-
-Track::Track(Segment* pSegment, long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      content_encoding_entries_(NULL),
-      content_encoding_entries_end_(NULL) {}
-
-Track::~Track() {
-  Info& info = const_cast<Info&>(m_info);
-  info.Clear();
-
-  ContentEncoding** i = content_encoding_entries_;
-  ContentEncoding** const j = content_encoding_entries_end_;
-
-  while (i != j) {
-    ContentEncoding* const encoding = *i++;
-    delete encoding;
-  }
-
-  delete[] content_encoding_entries_;
-}
-
-long Track::Create(Segment* pSegment, const Info& info, long long element_start,
-                   long long element_size, Track*& pResult) {
-  if (pResult)
-    return -1;
-
-  Track* const pTrack =
-      new (std::nothrow) Track(pSegment, element_start, element_size);
-
-  if (pTrack == NULL)
-    return -1;  // generic error
-
-  const int status = info.Copy(pTrack->m_info);
-
-  if (status) {  // error
-    delete pTrack;
-    return status;
-  }
-
-  pResult = pTrack;
-  return 0;  // success
-}
-
-Track::Info::Info()
-    : uid(0),
-      defaultDuration(0),
-      codecDelay(0),
-      seekPreRoll(0),
-      nameAsUTF8(NULL),
-      language(NULL),
-      codecId(NULL),
-      codecNameAsUTF8(NULL),
-      codecPrivate(NULL),
-      codecPrivateSize(0),
-      lacing(false) {}
-
-Track::Info::~Info() { Clear(); }
-
-void Track::Info::Clear() {
-  delete[] nameAsUTF8;
-  nameAsUTF8 = NULL;
-
-  delete[] language;
-  language = NULL;
-
-  delete[] codecId;
-  codecId = NULL;
-
-  delete[] codecPrivate;
-  codecPrivate = NULL;
-  codecPrivateSize = 0;
-
-  delete[] codecNameAsUTF8;
-  codecNameAsUTF8 = NULL;
-}
-
-int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
-  if (str == static_cast<char * Info::*>(NULL))
-    return -1;
-
-  char*& dst = dst_.*str;
-
-  if (dst)  // should be NULL already
-    return -1;
-
-  const char* const src = this->*str;
-
-  if (src == NULL)
-    return 0;
-
-  const size_t len = strlen(src);
-
-  dst = SafeArrayAlloc<char>(1, len + 1);
-
-  if (dst == NULL)
-    return -1;
-
-  strcpy(dst, src);
-
-  return 0;
-}
-
-int Track::Info::Copy(Info& dst) const {
-  if (&dst == this)
-    return 0;
-
-  dst.type = type;
-  dst.number = number;
-  dst.defaultDuration = defaultDuration;
-  dst.codecDelay = codecDelay;
-  dst.seekPreRoll = seekPreRoll;
-  dst.uid = uid;
-  dst.lacing = lacing;
-  dst.settings = settings;
-
-  // We now copy the string member variables from src to dst.
-  // This involves memory allocation so in principle the operation
-  // can fail (indeed, that's why we have Info::Copy), so we must
-  // report this to the caller.  An error return from this function
-  // therefore implies that the copy was only partially successful.
-
-  if (int status = CopyStr(&Info::nameAsUTF8, dst))
-    return status;
-
-  if (int status = CopyStr(&Info::language, dst))
-    return status;
-
-  if (int status = CopyStr(&Info::codecId, dst))
-    return status;
-
-  if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
-    return status;
-
-  if (codecPrivateSize > 0) {
-    if (codecPrivate == NULL)
-      return -1;
-
-    if (dst.codecPrivate)
-      return -1;
-
-    if (dst.codecPrivateSize != 0)
-      return -1;
-
-    dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
-
-    if (dst.codecPrivate == NULL)
-      return -1;
-
-    memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
-    dst.codecPrivateSize = codecPrivateSize;
-  }
-
-  return 0;
-}
-
-const BlockEntry* Track::GetEOS() const { return &m_eos; }
-
-long Track::GetType() const { return m_info.type; }
-
-long Track::GetNumber() const { return m_info.number; }
-
-unsigned long long Track::GetUid() const { return m_info.uid; }
-
-const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
-
-const char* Track::GetLanguage() const { return m_info.language; }
-
-const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
-
-const char* Track::GetCodecId() const { return m_info.codecId; }
-
-const unsigned char* Track::GetCodecPrivate(size_t& size) const {
-  size = m_info.codecPrivateSize;
-  return m_info.codecPrivate;
-}
-
-bool Track::GetLacing() const { return m_info.lacing; }
-
-unsigned long long Track::GetDefaultDuration() const {
-  return m_info.defaultDuration;
-}
-
-unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
-
-unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
-
-long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
-  const Cluster* pCluster = m_pSegment->GetFirst();
-
-  for (int i = 0;;) {
-    if (pCluster == NULL) {
-      pBlockEntry = GetEOS();
-      return 1;
-    }
-
-    if (pCluster->EOS()) {
-      if (m_pSegment->DoneParsing()) {
-        pBlockEntry = GetEOS();
-        return 1;
-      }
-
-      pBlockEntry = 0;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long status = pCluster->GetFirst(pBlockEntry);
-
-    if (status < 0)  // error
-      return status;
-
-    if (pBlockEntry == 0) {  // empty cluster
-      pCluster = m_pSegment->GetNext(pCluster);
-      continue;
-    }
-
-    for (;;) {
-      const Block* const pBlock = pBlockEntry->GetBlock();
-      assert(pBlock);
-
-      const long long tn = pBlock->GetTrackNumber();
-
-      if ((tn == m_info.number) && VetEntry(pBlockEntry))
-        return 0;
-
-      const BlockEntry* pNextEntry;
-
-      status = pCluster->GetNext(pBlockEntry, pNextEntry);
-
-      if (status < 0)  // error
-        return status;
-
-      if (pNextEntry == 0)
-        break;
-
-      pBlockEntry = pNextEntry;
-    }
-
-    ++i;
-
-    if (i >= 100)
-      break;
-
-    pCluster = m_pSegment->GetNext(pCluster);
-  }
-
-  // NOTE: if we get here, it means that we didn't find a block with
-  // a matching track number.  We interpret that as an error (which
-  // might be too conservative).
-
-  pBlockEntry = GetEOS();  // so we can return a non-NULL value
-  return 1;
-}
-
-long Track::GetNext(const BlockEntry* pCurrEntry,
-                    const BlockEntry*& pNextEntry) const {
-  assert(pCurrEntry);
-  assert(!pCurrEntry->EOS());  //?
-
-  const Block* const pCurrBlock = pCurrEntry->GetBlock();
-  assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
-  if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
-    return -1;
-
-  const Cluster* pCluster = pCurrEntry->GetCluster();
-  assert(pCluster);
-  assert(!pCluster->EOS());
-
-  long status = pCluster->GetNext(pCurrEntry, pNextEntry);
-
-  if (status < 0)  // error
-    return status;
-
-  for (int i = 0;;) {
-    while (pNextEntry) {
-      const Block* const pNextBlock = pNextEntry->GetBlock();
-      assert(pNextBlock);
-
-      if (pNextBlock->GetTrackNumber() == m_info.number)
-        return 0;
-
-      pCurrEntry = pNextEntry;
-
-      status = pCluster->GetNext(pCurrEntry, pNextEntry);
-
-      if (status < 0)  // error
-        return status;
-    }
-
-    pCluster = m_pSegment->GetNext(pCluster);
-
-    if (pCluster == NULL) {
-      pNextEntry = GetEOS();
-      return 1;
-    }
-
-    if (pCluster->EOS()) {
-      if (m_pSegment->DoneParsing()) {
-        pNextEntry = GetEOS();
-        return 1;
-      }
-
-      // TODO: there is a potential O(n^2) problem here: we tell the
-      // caller to (pre)load another cluster, which he does, but then he
-      // calls GetNext again, which repeats the same search.  This is
-      // a pathological case, since the only way it can happen is if
-      // there exists a long sequence of clusters none of which contain a
-      // block from this track.  One way around this problem is for the
-      // caller to be smarter when he loads another cluster: don't call
-      // us back until you have a cluster that contains a block from this
-      // track. (Of course, that's not cheap either, since our caller
-      // would have to scan the each cluster as it's loaded, so that
-      // would just push back the problem.)
-
-      pNextEntry = NULL;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    status = pCluster->GetFirst(pNextEntry);
-
-    if (status < 0)  // error
-      return status;
-
-    if (pNextEntry == NULL)  // empty cluster
-      continue;
-
-    ++i;
-
-    if (i >= 100)
-      break;
-  }
-
-  // NOTE: if we get here, it means that we didn't find a block with
-  // a matching track number after lots of searching, so we give
-  // up trying.
-
-  pNextEntry = GetEOS();  // so we can return a non-NULL value
-  return 1;
-}
-
-bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
-  assert(pBlockEntry);
-  const Block* const pBlock = pBlockEntry->GetBlock();
-  assert(pBlock);
-  assert(pBlock->GetTrackNumber() == m_info.number);
-  if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
-    return false;
-
-  // This function is used during a seek to determine whether the
-  // frame is a valid seek target.  This default function simply
-  // returns true, which means all frames are valid seek targets.
-  // It gets overridden by the VideoTrack class, because only video
-  // keyframes can be used as seek target.
-
-  return true;
-}
-
-long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
-  const long status = GetFirst(pResult);
-
-  if (status < 0)  // buffer underflow, etc
-    return status;
-
-  assert(pResult);
-
-  if (pResult->EOS())
-    return 0;
-
-  const Cluster* pCluster = pResult->GetCluster();
-  assert(pCluster);
-  assert(pCluster->GetIndex() >= 0);
-
-  if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
-    return 0;
-
-  Cluster** const clusters = m_pSegment->m_clusters;
-  assert(clusters);
-
-  const long count = m_pSegment->GetCount();  // loaded only, not preloaded
-  assert(count > 0);
-
-  Cluster** const i = clusters + pCluster->GetIndex();
-  assert(i);
-  assert(*i == pCluster);
-  assert(pCluster->GetTime() <= time_ns);
-
-  Cluster** const j = clusters + count;
-
-  Cluster** lo = i;
-  Cluster** hi = j;
-
-  while (lo < hi) {
-    // INVARIANT:
-    //[i, lo) <= time_ns
-    //[lo, hi) ?
-    //[hi, j)  > time_ns
-
-    Cluster** const mid = lo + (hi - lo) / 2;
-    assert(mid < hi);
-
-    pCluster = *mid;
-    assert(pCluster);
-    assert(pCluster->GetIndex() >= 0);
-    assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
-
-    const long long t = pCluster->GetTime();
-
-    if (t <= time_ns)
-      lo = mid + 1;
-    else
-      hi = mid;
-
-    assert(lo <= hi);
-  }
-
-  assert(lo == hi);
-  assert(lo > i);
-  assert(lo <= j);
-
-  while (lo > i) {
-    pCluster = *--lo;
-    assert(pCluster);
-    assert(pCluster->GetTime() <= time_ns);
-
-    pResult = pCluster->GetEntry(this);
-
-    if ((pResult != 0) && !pResult->EOS())
-      return 0;
-
-    // landed on empty cluster (no entries)
-  }
-
-  pResult = GetEOS();  // weird
-  return 0;
-}
-
-const ContentEncoding* Track::GetContentEncodingByIndex(
-    unsigned long idx) const {
-  const ptrdiff_t count =
-      content_encoding_entries_end_ - content_encoding_entries_;
-  assert(count >= 0);
-
-  if (idx >= static_cast<unsigned long>(count))
-    return NULL;
-
-  return content_encoding_entries_[idx];
-}
-
-unsigned long Track::GetContentEncodingCount() const {
-  const ptrdiff_t count =
-      content_encoding_entries_end_ - content_encoding_entries_;
-  assert(count >= 0);
-
-  return static_cast<unsigned long>(count);
-}
-
-long Track::ParseContentEncodingsEntry(long long start, long long size) {
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-  assert(pReader);
-
-  long long pos = start;
-  const long long stop = start + size;
-
-  // Count ContentEncoding elements.
-  int count = 0;
-  while (pos < stop) {
-    long long id, size;
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    // pos now designates start of element
-    if (id == mkvmuxer::kMkvContentEncoding)
-      ++count;
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (count <= 0)
-    return -1;
-
-  content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
-  if (!content_encoding_entries_)
-    return -1;
-
-  content_encoding_entries_end_ = content_encoding_entries_;
-
-  pos = start;
-  while (pos < stop) {
-    long long id, size;
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-    if (status < 0)  // error
-      return status;
-
-    // pos now designates start of element
-    if (id == mkvmuxer::kMkvContentEncoding) {
-      ContentEncoding* const content_encoding =
-          new (std::nothrow) ContentEncoding();
-      if (!content_encoding)
-        return -1;
-
-      status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
-      if (status) {
-        delete content_encoding;
-        return status;
-      }
-
-      *content_encoding_entries_end_++ = content_encoding;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;
-}
-
-Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
-
-BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
-
-const Block* Track::EOSBlock::GetBlock() const { return NULL; }
-
-VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
-                       long long element_size)
-    : Track(pSegment, element_start, element_size) {}
-
-long VideoTrack::Parse(Segment* pSegment, const Info& info,
-                       long long element_start, long long element_size,
-                       VideoTrack*& pResult) {
-  if (pResult)
-    return -1;
-
-  if (info.type != Track::kVideo)
-    return -1;
-
-  long long width = 0;
-  long long height = 0;
-  long long display_width = 0;
-  long long display_height = 0;
-  long long display_unit = 0;
-  long long stereo_mode = 0;
-
-  double rate = 0.0;
-
-  IMkvReader* const pReader = pSegment->m_pReader;
-
-  const Settings& s = info.settings;
-  assert(s.start >= 0);
-  assert(s.size >= 0);
-
-  long long pos = s.start;
-  assert(pos >= 0);
-
-  const long long stop = pos + s.size;
-
-  while (pos < stop) {
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvPixelWidth) {
-      width = UnserializeUInt(pReader, pos, size);
-
-      if (width <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvPixelHeight) {
-      height = UnserializeUInt(pReader, pos, size);
-
-      if (height <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayWidth) {
-      display_width = UnserializeUInt(pReader, pos, size);
-
-      if (display_width <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayHeight) {
-      display_height = UnserializeUInt(pReader, pos, size);
-
-      if (display_height <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvDisplayUnit) {
-      display_unit = UnserializeUInt(pReader, pos, size);
-
-      if (display_unit < 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvStereoMode) {
-      stereo_mode = UnserializeUInt(pReader, pos, size);
-
-      if (stereo_mode < 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvFrameRate) {
-      const long status = UnserializeFloat(pReader, pos, size, rate);
-
-      if (status < 0)
-        return status;
-
-      if (rate <= 0)
-        return E_FILE_FORMAT_INVALID;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  VideoTrack* const pTrack =
-      new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
-
-  if (pTrack == NULL)
-    return -1;  // generic error
-
-  const int status = info.Copy(pTrack->m_info);
-
-  if (status) {  // error
-    delete pTrack;
-    return status;
-  }
-
-  pTrack->m_width = width;
-  pTrack->m_height = height;
-  pTrack->m_display_width = display_width;
-  pTrack->m_display_height = display_height;
-  pTrack->m_display_unit = display_unit;
-  pTrack->m_stereo_mode = stereo_mode;
-  pTrack->m_rate = rate;
-
-  pResult = pTrack;
-  return 0;  // success
-}
-
-bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
-  return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
-}
-
-long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
-  const long status = GetFirst(pResult);
-
-  if (status < 0)  // buffer underflow, etc
-    return status;
-
-  assert(pResult);
-
-  if (pResult->EOS())
-    return 0;
-
-  const Cluster* pCluster = pResult->GetCluster();
-  assert(pCluster);
-  assert(pCluster->GetIndex() >= 0);
-
-  if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
-    return 0;
-
-  Cluster** const clusters = m_pSegment->m_clusters;
-  assert(clusters);
-
-  const long count = m_pSegment->GetCount();  // loaded only, not pre-loaded
-  assert(count > 0);
-
-  Cluster** const i = clusters + pCluster->GetIndex();
-  assert(i);
-  assert(*i == pCluster);
-  assert(pCluster->GetTime() <= time_ns);
-
-  Cluster** const j = clusters + count;
-
-  Cluster** lo = i;
-  Cluster** hi = j;
-
-  while (lo < hi) {
-    // INVARIANT:
-    //[i, lo) <= time_ns
-    //[lo, hi) ?
-    //[hi, j)  > time_ns
-
-    Cluster** const mid = lo + (hi - lo) / 2;
-    assert(mid < hi);
-
-    pCluster = *mid;
-    assert(pCluster);
-    assert(pCluster->GetIndex() >= 0);
-    assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
-
-    const long long t = pCluster->GetTime();
-
-    if (t <= time_ns)
-      lo = mid + 1;
-    else
-      hi = mid;
-
-    assert(lo <= hi);
-  }
-
-  assert(lo == hi);
-  assert(lo > i);
-  assert(lo <= j);
-
-  pCluster = *--lo;
-  assert(pCluster);
-  assert(pCluster->GetTime() <= time_ns);
-
-  pResult = pCluster->GetEntry(this, time_ns);
-
-  if ((pResult != 0) && !pResult->EOS())  // found a keyframe
-    return 0;
-
-  while (lo != i) {
-    pCluster = *--lo;
-    assert(pCluster);
-    assert(pCluster->GetTime() <= time_ns);
-
-    pResult = pCluster->GetEntry(this, time_ns);
-
-    if ((pResult != 0) && !pResult->EOS())
-      return 0;
-  }
-
-  // weird: we're on the first cluster, but no keyframe found
-  // should never happen but we must return something anyway
-
-  pResult = GetEOS();
-  return 0;
-}
-
-long long VideoTrack::GetWidth() const { return m_width; }
-
-long long VideoTrack::GetHeight() const { return m_height; }
-
-long long VideoTrack::GetDisplayWidth() const {
-  return m_display_width > 0 ? m_display_width : GetWidth();
-}
-
-long long VideoTrack::GetDisplayHeight() const {
-  return m_display_height > 0 ? m_display_height : GetHeight();
-}
-
-long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
-
-long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
-
-double VideoTrack::GetFrameRate() const { return m_rate; }
-
-AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
-                       long long element_size)
-    : Track(pSegment, element_start, element_size) {}
-
-long AudioTrack::Parse(Segment* pSegment, const Info& info,
-                       long long element_start, long long element_size,
-                       AudioTrack*& pResult) {
-  if (pResult)
-    return -1;
-
-  if (info.type != Track::kAudio)
-    return -1;
-
-  IMkvReader* const pReader = pSegment->m_pReader;
-
-  const Settings& s = info.settings;
-  assert(s.start >= 0);
-  assert(s.size >= 0);
-
-  long long pos = s.start;
-  assert(pos >= 0);
-
-  const long long stop = pos + s.size;
-
-  double rate = 8000.0;  // MKV default
-  long long channels = 1;
-  long long bit_depth = 0;
-
-  while (pos < stop) {
-    long long id, size;
-
-    long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (id == mkvmuxer::kMkvSamplingFrequency) {
-      status = UnserializeFloat(pReader, pos, size, rate);
-
-      if (status < 0)
-        return status;
-
-      if (rate <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvChannels) {
-      channels = UnserializeUInt(pReader, pos, size);
-
-      if (channels <= 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvBitDepth) {
-      bit_depth = UnserializeUInt(pReader, pos, size);
-
-      if (bit_depth <= 0)
-        return E_FILE_FORMAT_INVALID;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  AudioTrack* const pTrack =
-      new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
-
-  if (pTrack == NULL)
-    return -1;  // generic error
-
-  const int status = info.Copy(pTrack->m_info);
-
-  if (status) {
-    delete pTrack;
-    return status;
-  }
-
-  pTrack->m_rate = rate;
-  pTrack->m_channels = channels;
-  pTrack->m_bitDepth = bit_depth;
-
-  pResult = pTrack;
-  return 0;  // success
-}
-
-double AudioTrack::GetSamplingRate() const { return m_rate; }
-
-long long AudioTrack::GetChannels() const { return m_channels; }
-
-long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
-
-Tracks::Tracks(Segment* pSegment, long long start, long long size_,
-               long long element_start, long long element_size)
-    : m_pSegment(pSegment),
-      m_start(start),
-      m_size(size_),
-      m_element_start(element_start),
-      m_element_size(element_size),
-      m_trackEntries(NULL),
-      m_trackEntriesEnd(NULL) {}
-
-long Tracks::Parse() {
-  assert(m_trackEntries == NULL);
-  assert(m_trackEntriesEnd == NULL);
-
-  const long long stop = m_start + m_size;
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  int count = 0;
-  long long pos = m_start;
-
-  while (pos < stop) {
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size == 0)  // weird
-      continue;
-
-    if (id == mkvmuxer::kMkvTrackEntry)
-      ++count;
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if (count <= 0)
-    return 0;  // success
-
-  m_trackEntries = new (std::nothrow) Track*[count];
-
-  if (m_trackEntries == NULL)
-    return -1;
-
-  m_trackEntriesEnd = m_trackEntries;
-
-  pos = m_start;
-
-  while (pos < stop) {
-    const long long element_start = pos;
-
-    long long id, payload_size;
-
-    const long status =
-        ParseElementHeader(pReader, pos, stop, id, payload_size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (payload_size == 0)  // weird
-      continue;
-
-    const long long payload_stop = pos + payload_size;
-    assert(payload_stop <= stop);  // checked in ParseElement
-
-    const long long element_size = payload_stop - element_start;
-
-    if (id == mkvmuxer::kMkvTrackEntry) {
-      Track*& pTrack = *m_trackEntriesEnd;
-      pTrack = NULL;
-
-      const long status = ParseTrackEntry(pos, payload_size, element_start,
-                                          element_size, pTrack);
-      if (status)
-        return status;
-
-      if (pTrack)
-        ++m_trackEntriesEnd;
-    }
-
-    pos = payload_stop;
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-
-  return 0;  // success
-}
-
-unsigned long Tracks::GetTracksCount() const {
-  const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
-  assert(result >= 0);
-
-  return static_cast<unsigned long>(result);
-}
-
-long Tracks::ParseTrackEntry(long long track_start, long long track_size,
-                             long long element_start, long long element_size,
-                             Track*& pResult) const {
-  if (pResult)
-    return -1;
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = track_start;
-  const long long track_stop = track_start + track_size;
-
-  Track::Info info;
-
-  info.type = 0;
-  info.number = 0;
-  info.uid = 0;
-  info.defaultDuration = 0;
-
-  Track::Settings v;
-  v.start = -1;
-  v.size = -1;
-
-  Track::Settings a;
-  a.start = -1;
-  a.size = -1;
-
-  Track::Settings e;  // content_encodings_settings;
-  e.start = -1;
-  e.size = -1;
-
-  long long lacing = 1;  // default is true
-
-  while (pos < track_stop) {
-    long long id, size;
-
-    const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
-
-    if (status < 0)  // error
-      return status;
-
-    if (size < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    const long long start = pos;
-
-    if (id == mkvmuxer::kMkvVideo) {
-      v.start = start;
-      v.size = size;
-    } else if (id == mkvmuxer::kMkvAudio) {
-      a.start = start;
-      a.size = size;
-    } else if (id == mkvmuxer::kMkvContentEncodings) {
-      e.start = start;
-      e.size = size;
-    } else if (id == mkvmuxer::kMkvTrackUID) {
-      if (size > 8)
-        return E_FILE_FORMAT_INVALID;
-
-      info.uid = 0;
-
-      long long pos_ = start;
-      const long long pos_end = start + size;
-
-      while (pos_ != pos_end) {
-        unsigned char b;
-
-        const int status = pReader->Read(pos_, 1, &b);
-
-        if (status)
-          return status;
-
-        info.uid <<= 8;
-        info.uid |= b;
-
-        ++pos_;
-      }
-    } else if (id == mkvmuxer::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) {
-      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) {
-      const long status =
-          UnserializeString(pReader, pos, size, info.nameAsUTF8);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvLanguage) {
-      const long status = UnserializeString(pReader, pos, size, info.language);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::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) {
-      const long status = UnserializeString(pReader, pos, size, info.codecId);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvFlagLacing) {
-      lacing = UnserializeUInt(pReader, pos, size);
-
-      if ((lacing < 0) || (lacing > 1))
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvCodecPrivate) {
-      delete[] info.codecPrivate;
-      info.codecPrivate = NULL;
-      info.codecPrivateSize = 0;
-
-      const size_t buflen = static_cast<size_t>(size);
-
-      if (buflen) {
-        unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
-
-        if (buf == NULL)
-          return -1;
-
-        const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
-
-        if (status) {
-          delete[] buf;
-          return status;
-        }
-
-        info.codecPrivate = buf;
-        info.codecPrivateSize = buflen;
-      }
-    } else if (id == mkvmuxer::kMkvCodecName) {
-      const long status =
-          UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
-
-      if (status)
-        return status;
-    } else if (id == mkvmuxer::kMkvCodecDelay) {
-      info.codecDelay = UnserializeUInt(pReader, pos, size);
-    } else if (id == mkvmuxer::kMkvSeekPreRoll) {
-      info.seekPreRoll = UnserializeUInt(pReader, pos, size);
-    }
-
-    pos += size;  // consume payload
-    if (pos > track_stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != track_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if (info.number <= 0)  // not specified
-    return E_FILE_FORMAT_INVALID;
-
-  if (GetTrackByNumber(info.number))
-    return E_FILE_FORMAT_INVALID;
-
-  if (info.type <= 0)  // not specified
-    return E_FILE_FORMAT_INVALID;
-
-  info.lacing = (lacing > 0) ? true : false;
-
-  if (info.type == Track::kVideo) {
-    if (v.start < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (a.start >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    info.settings = v;
-
-    VideoTrack* pTrack = NULL;
-
-    const long status = VideoTrack::Parse(m_pSegment, info, element_start,
-                                          element_size, pTrack);
-
-    if (status)
-      return status;
-
-    pResult = pTrack;
-    assert(pResult);
-
-    if (e.start >= 0)
-      pResult->ParseContentEncodingsEntry(e.start, e.size);
-  } else if (info.type == Track::kAudio) {
-    if (a.start < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (v.start >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    info.settings = a;
-
-    AudioTrack* pTrack = NULL;
-
-    const long status = AudioTrack::Parse(m_pSegment, info, element_start,
-                                          element_size, pTrack);
-
-    if (status)
-      return status;
-
-    pResult = pTrack;
-    assert(pResult);
-
-    if (e.start >= 0)
-      pResult->ParseContentEncodingsEntry(e.start, e.size);
-  } else {
-    // neither video nor audio - probably metadata or subtitles
-
-    if (a.start >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (v.start >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (info.type == Track::kMetadata && e.start >= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    info.settings.start = -1;
-    info.settings.size = 0;
-
-    Track* pTrack = NULL;
-
-    const long status =
-        Track::Create(m_pSegment, info, element_start, element_size, pTrack);
-
-    if (status)
-      return status;
-
-    pResult = pTrack;
-    assert(pResult);
-  }
-
-  return 0;  // success
-}
-
-Tracks::~Tracks() {
-  Track** i = m_trackEntries;
-  Track** const j = m_trackEntriesEnd;
-
-  while (i != j) {
-    Track* const pTrack = *i++;
-    delete pTrack;
-  }
-
-  delete[] m_trackEntries;
-}
-
-const Track* Tracks::GetTrackByNumber(long tn) const {
-  if (tn < 0)
-    return NULL;
-
-  Track** i = m_trackEntries;
-  Track** const j = m_trackEntriesEnd;
-
-  while (i != j) {
-    Track* const pTrack = *i++;
-
-    if (pTrack == NULL)
-      continue;
-
-    if (tn == pTrack->GetNumber())
-      return pTrack;
-  }
-
-  return NULL;  // not found
-}
-
-const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
-  const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
-
-  if (idx >= static_cast<unsigned long>(count))
-    return NULL;
-
-  return m_trackEntries[idx];
-}
-
-long Cluster::Load(long long& pos, long& len) const {
-  if (m_pSegment == NULL)
-    return E_PARSE_FAILED;
-
-  if (m_timecode >= 0)  // at least partially loaded
-    return 0;
-
-  if (m_pos != m_element_start || m_element_size >= 0)
-    return E_PARSE_FAILED;
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-  long long total, avail;
-  const int status = pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  if (total >= 0 && (avail > total || m_pos > total))
-    return E_FILE_FORMAT_INVALID;
-
-  pos = m_pos;
-
-  long long cluster_size = -1;
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  long long result = GetUIntLength(pReader, pos, len);
-
-  if (result < 0)  // error or underflow
-    return static_cast<long>(result);
-
-  if (result > 0)
-    return E_BUFFER_NOT_FULL;
-
-  if ((pos + len) > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long id_ = ReadID(pReader, pos, len);
-
-  if (id_ < 0)  // error
-    return static_cast<long>(id_);
-
-  if (id_ != mkvmuxer::kMkvCluster)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume id
-
-  // read cluster size
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  result = GetUIntLength(pReader, pos, len);
-
-  if (result < 0)  // error
-    return static_cast<long>(result);
-
-  if (result > 0)
-    return E_BUFFER_NOT_FULL;
-
-  if ((pos + len) > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long size = ReadUInt(pReader, pos, len);
-
-  if (size < 0)  // error
-    return static_cast<long>(cluster_size);
-
-  if (size == 0)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume length of size of element
-
-  const long long unknown_size = (1LL << (7 * len)) - 1;
-
-  if (size != unknown_size)
-    cluster_size = size;
-
-  // pos points to start of payload
-  long long timecode = -1;
-  long long new_pos = -1;
-  bool bBlock = false;
-
-  long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
-
-  for (;;) {
-    if ((cluster_stop >= 0) && (pos >= cluster_stop))
-      break;
-
-    // Parse ID
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)  // error
-      return static_cast<long>(id);
-
-    if (id == 0)
-      return E_FILE_FORMAT_INVALID;
-
-    // This is the distinguished set of ID's we use to determine
-    // that we have exhausted the sub-element's inside the cluster
-    // whose ID we parsed earlier.
-
-    if (id == mkvmuxer::kMkvCluster)
-      break;
-
-    if (id == mkvmuxer::kMkvCues)
-      break;
-
-    pos += len;  // consume ID field
-
-    // Parse Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size == unknown_size)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume size field
-
-    if ((cluster_stop >= 0) && (pos > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    // pos now points to start of payload
-
-    if (size == 0)
-      continue;
-
-    if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if (id == mkvmuxer::kMkvTimecode) {
-      len = static_cast<long>(size);
-
-      if ((pos + size) > avail)
-        return E_BUFFER_NOT_FULL;
-
-      timecode = UnserializeUInt(pReader, pos, size);
-
-      if (timecode < 0)  // error (or underflow)
-        return static_cast<long>(timecode);
-
-      new_pos = pos + size;
-
-      if (bBlock)
-        break;
-    } else if (id == mkvmuxer::kMkvBlockGroup) {
-      bBlock = true;
-      break;
-    } else if (id == mkvmuxer::kMkvSimpleBlock) {
-      bBlock = true;
-      break;
-    }
-
-    pos += size;  // consume payload
-    if (cluster_stop >= 0 && pos > cluster_stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (cluster_stop >= 0 && pos > cluster_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if (timecode < 0)  // no timecode found
-    return E_FILE_FORMAT_INVALID;
-
-  if (!bBlock)
-    return E_FILE_FORMAT_INVALID;
-
-  m_pos = new_pos;  // designates position just beyond timecode payload
-  m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
-
-  if (cluster_size >= 0)
-    m_element_size = cluster_stop - m_element_start;
-
-  return 0;
-}
-
-long Cluster::Parse(long long& pos, long& len) const {
-  long status = Load(pos, len);
-
-  if (status < 0)
-    return status;
-
-  if (m_pos < m_element_start || m_timecode < 0)
-    return E_PARSE_FAILED;
-
-  const long long cluster_stop =
-      (m_element_size < 0) ? -1 : m_element_start + m_element_size;
-
-  if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
-    return 1;  // nothing else to do
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long total, avail;
-
-  status = pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  if (total >= 0 && avail > total)
-    return E_FILE_FORMAT_INVALID;
-
-  pos = m_pos;
-
-  for (;;) {
-    if ((cluster_stop >= 0) && (pos >= cluster_stop))
-      break;
-
-    if ((total >= 0) && (pos >= total)) {
-      if (m_element_size < 0)
-        m_element_size = pos - m_element_start;
-
-      break;
-    }
-
-    // Parse ID
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)
-      return E_FILE_FORMAT_INVALID;
-
-    // This is the distinguished set of ID's we use to determine
-    // that we have exhausted the sub-element's inside the cluster
-    // whose ID we parsed earlier.
-
-    if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) {
-      if (m_element_size < 0)
-        m_element_size = pos - m_element_start;
-
-      break;
-    }
-
-    pos += len;  // consume ID field
-
-    // Parse Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size == unknown_size)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume size field
-
-    if ((cluster_stop >= 0) && (pos > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    // pos now points to start of payload
-
-    if (size == 0)
-      continue;
-
-    // const long long block_start = pos;
-    const long long block_stop = pos + size;
-
-    if (cluster_stop >= 0) {
-      if (block_stop > cluster_stop) {
-        if (id == mkvmuxer::kMkvBlockGroup ||
-            id == mkvmuxer::kMkvSimpleBlock) {
-          return E_FILE_FORMAT_INVALID;
-        }
-
-        pos = cluster_stop;
-        break;
-      }
-    } else if ((total >= 0) && (block_stop > total)) {
-      m_element_size = total - m_element_start;
-      pos = total;
-      break;
-    } else if (block_stop > avail) {
-      len = static_cast<long>(size);
-      return E_BUFFER_NOT_FULL;
-    }
-
-    Cluster* const this_ = const_cast<Cluster*>(this);
-
-    if (id == mkvmuxer::kMkvBlockGroup)
-      return this_->ParseBlockGroup(size, pos, len);
-
-    if (id == mkvmuxer::kMkvSimpleBlock)
-      return this_->ParseSimpleBlock(size, pos, len);
-
-    pos += size;  // consume payload
-    if (cluster_stop >= 0 && pos > cluster_stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (m_element_size < 1)
-    return E_FILE_FORMAT_INVALID;
-
-  m_pos = pos;
-  if (cluster_stop >= 0 && m_pos > cluster_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if (m_entries_count > 0) {
-    const long idx = m_entries_count - 1;
-
-    const BlockEntry* const pLast = m_entries[idx];
-    if (pLast == NULL)
-      return E_PARSE_FAILED;
-
-    const Block* const pBlock = pLast->GetBlock();
-    if (pBlock == NULL)
-      return E_PARSE_FAILED;
-
-    const long long start = pBlock->m_start;
-
-    if ((total >= 0) && (start > total))
-      return E_PARSE_FAILED;  // defend against trucated stream
-
-    const long long size = pBlock->m_size;
-
-    const long long stop = start + size;
-    if (cluster_stop >= 0 && stop > cluster_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((total >= 0) && (stop > total))
-      return E_PARSE_FAILED;  // defend against trucated stream
-  }
-
-  return 1;  // no more entries
-}
-
-long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
-                               long& len) {
-  const long long block_start = pos;
-  const long long block_stop = pos + block_size;
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long total, avail;
-
-  long status = pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  // parse track number
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  long long result = GetUIntLength(pReader, pos, len);
-
-  if (result < 0)  // error
-    return static_cast<long>(result);
-
-  if (result > 0)  // weird
-    return E_BUFFER_NOT_FULL;
-
-  if ((pos + len) > block_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + len) > avail)
-    return E_BUFFER_NOT_FULL;
-
-  const long long track = ReadUInt(pReader, pos, len);
-
-  if (track < 0)  // error
-    return static_cast<long>(track);
-
-  if (track == 0)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume track number
-
-  if ((pos + 2) > block_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + 2) > avail) {
-    len = 2;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  pos += 2;  // consume timecode
-
-  if ((pos + 1) > block_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + 1) > avail) {
-    len = 1;
-    return E_BUFFER_NOT_FULL;
-  }
-
-  unsigned char flags;
-
-  status = pReader->Read(pos, 1, &flags);
-
-  if (status < 0) {  // error or underflow
-    len = 1;
-    return status;
-  }
-
-  ++pos;  // consume flags byte
-  assert(pos <= avail);
-
-  if (pos >= block_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  const int lacing = int(flags & 0x06) >> 1;
-
-  if ((lacing != 0) && (block_stop > avail)) {
-    len = static_cast<long>(block_stop - pos);
-    return E_BUFFER_NOT_FULL;
-  }
-
-  status = CreateBlock(mkvmuxer::kMkvSimpleBlock,
-                       block_start, block_size,
-                       0);  // DiscardPadding
-
-  if (status != 0)
-    return status;
-
-  m_pos = block_stop;
-
-  return 0;  // success
-}
-
-long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
-                              long& len) {
-  const long long payload_start = pos;
-  const long long payload_stop = pos + payload_size;
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long total, avail;
-
-  long status = pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  if ((total >= 0) && (payload_stop > total))
-    return E_FILE_FORMAT_INVALID;
-
-  if (payload_stop > avail) {
-    len = static_cast<long>(payload_size);
-    return E_BUFFER_NOT_FULL;
-  }
-
-  long long discard_padding = 0;
-
-  while (pos < payload_stop) {
-    // parse sub-block element ID
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((pos + len) > payload_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)  // error
-      return static_cast<long>(id);
-
-    if (id == 0)  // not a valid ID
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume ID field
-
-    // Parse Size
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((pos + len) > payload_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    pos += len;  // consume size field
-
-    // pos now points to start of sub-block group payload
-
-    if (pos > payload_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if (size == 0)  // weird
-      continue;
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size == unknown_size)
-      return E_FILE_FORMAT_INVALID;
-
-    if (id == mkvmuxer::kMkvDiscardPadding) {
-      status = UnserializeInt(pReader, pos, size, discard_padding);
-
-      if (status < 0)  // error
-        return status;
-    }
-
-    if (id != mkvmuxer::kMkvBlock) {
-      pos += size;  // consume sub-part of block group
-
-      if (pos > payload_stop)
-        return E_FILE_FORMAT_INVALID;
-
-      continue;
-    }
-
-    const long long block_stop = pos + size;
-
-    if (block_stop > payload_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    // parse track number
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((pos + len) > block_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long track = ReadUInt(pReader, pos, len);
-
-    if (track < 0)  // error
-      return static_cast<long>(track);
-
-    if (track == 0)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume track number
-
-    if ((pos + 2) > block_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + 2) > avail) {
-      len = 2;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    pos += 2;  // consume timecode
-
-    if ((pos + 1) > block_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    unsigned char flags;
-
-    status = pReader->Read(pos, 1, &flags);
-
-    if (status < 0) {  // error or underflow
-      len = 1;
-      return status;
-    }
-
-    ++pos;  // consume flags byte
-    assert(pos <= avail);
-
-    if (pos >= block_stop)
-      return E_FILE_FORMAT_INVALID;
-
-    const int lacing = int(flags & 0x06) >> 1;
-
-    if ((lacing != 0) && (block_stop > avail)) {
-      len = static_cast<long>(block_stop - pos);
-      return E_BUFFER_NOT_FULL;
-    }
-
-    pos = block_stop;  // consume block-part of block group
-    if (pos > payload_stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  if (pos != payload_stop)
-    return E_FILE_FORMAT_INVALID;
-
-  status = CreateBlock(mkvmuxer::kMkvBlockGroup,
-                       payload_start, payload_size, discard_padding);
-  if (status != 0)
-    return status;
-
-  m_pos = payload_stop;
-
-  return 0;  // success
-}
-
-long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
-  assert(m_pos >= m_element_start);
-
-  pEntry = NULL;
-
-  if (index < 0)
-    return -1;  // generic error
-
-  if (m_entries_count < 0)
-    return E_BUFFER_NOT_FULL;
-
-  assert(m_entries);
-  assert(m_entries_size > 0);
-  assert(m_entries_count <= m_entries_size);
-
-  if (index < m_entries_count) {
-    pEntry = m_entries[index];
-    assert(pEntry);
-
-    return 1;  // found entry
-  }
-
-  if (m_element_size < 0)  // we don't know cluster end yet
-    return E_BUFFER_NOT_FULL;  // underflow
-
-  const long long element_stop = m_element_start + m_element_size;
-
-  if (m_pos >= element_stop)
-    return 0;  // nothing left to parse
-
-  return E_BUFFER_NOT_FULL;  // underflow, since more remains to be parsed
-}
-
-Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
-  if (!pSegment || off < 0)
-    return NULL;
-
-  const long long element_start = pSegment->m_start + off;
-
-  Cluster* const pCluster =
-      new (std::nothrow) Cluster(pSegment, idx, element_start);
-
-  return pCluster;
-}
-
-Cluster::Cluster()
-    : m_pSegment(NULL),
-      m_element_start(0),
-      m_index(0),
-      m_pos(0),
-      m_element_size(0),
-      m_timecode(0),
-      m_entries(NULL),
-      m_entries_size(0),
-      m_entries_count(0)  // means "no entries"
-{}
-
-Cluster::Cluster(Segment* pSegment, long idx, long long element_start
-                 /* long long element_size */)
-    : m_pSegment(pSegment),
-      m_element_start(element_start),
-      m_index(idx),
-      m_pos(element_start),
-      m_element_size(-1 /* element_size */),
-      m_timecode(-1),
-      m_entries(NULL),
-      m_entries_size(0),
-      m_entries_count(-1)  // means "has not been parsed yet"
-{}
-
-Cluster::~Cluster() {
-  if (m_entries_count <= 0)
-    return;
-
-  BlockEntry** i = m_entries;
-  BlockEntry** const j = m_entries + m_entries_count;
-
-  while (i != j) {
-    BlockEntry* p = *i++;
-    assert(p);
-
-    delete p;
-  }
-
-  delete[] m_entries;
-}
-
-bool Cluster::EOS() const { return (m_pSegment == NULL); }
-
-long Cluster::GetIndex() const { return m_index; }
-
-long long Cluster::GetPosition() const {
-  const long long pos = m_element_start - m_pSegment->m_start;
-  assert(pos >= 0);
-
-  return pos;
-}
-
-long long Cluster::GetElementSize() const { return m_element_size; }
-
-long Cluster::HasBlockEntries(
-    const Segment* pSegment,
-    long long off,  // relative to start of segment payload
-    long long& pos, long& len) {
-  assert(pSegment);
-  assert(off >= 0);  // relative to segment
-
-  IMkvReader* const pReader = pSegment->m_pReader;
-
-  long long total, avail;
-
-  long status = pReader->Length(&total, &avail);
-
-  if (status < 0)  // error
-    return status;
-
-  assert((total < 0) || (avail <= total));
-
-  pos = pSegment->m_start + off;  // absolute
-
-  if ((total >= 0) && (pos >= total))
-    return 0;  // we don't even have a complete cluster
-
-  const long long segment_stop =
-      (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
-
-  long long cluster_stop = -1;  // interpreted later to mean "unknown size"
-
-  {
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // need more data
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((total >= 0) && ((pos + len) > total))
-      return 0;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)  // error
-      return static_cast<long>(id);
-
-    if (id != mkvmuxer::kMkvCluster)
-      return E_PARSE_FAILED;
-
-    pos += len;  // consume Cluster ID field
-
-    // read size field
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // weird
-      return E_BUFFER_NOT_FULL;
-
-    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((total >= 0) && ((pos + len) > total))
-      return 0;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    if (size == 0)
-      return 0;  // cluster does not have entries
-
-    pos += len;  // consume size field
-
-    // pos now points to start of payload
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size != unknown_size) {
-      cluster_stop = pos + size;
-      assert(cluster_stop >= 0);
-
-      if ((segment_stop >= 0) && (cluster_stop > segment_stop))
-        return E_FILE_FORMAT_INVALID;
-
-      if ((total >= 0) && (cluster_stop > total))
-        // return E_FILE_FORMAT_INVALID;  //too conservative
-        return 0;  // cluster does not have any entries
-    }
-  }
-
-  for (;;) {
-    if ((cluster_stop >= 0) && (pos >= cluster_stop))
-      return 0;  // no entries detected
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    long long result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // need more data
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long id = ReadID(pReader, pos, len);
-
-    if (id < 0)  // error
-      return static_cast<long>(id);
-
-    // This is the distinguished set of ID's we use to determine
-    // that we have exhausted the sub-element's inside the cluster
-    // whose ID we parsed earlier.
-
-    if (id == mkvmuxer::kMkvCluster)
-      return 0;  // no entries found
-
-    if (id == mkvmuxer::kMkvCues)
-      return 0;  // no entries found
-
-    pos += len;  // consume id field
-
-    if ((cluster_stop >= 0) && (pos >= cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    // read size field
-
-    if ((pos + 1) > avail) {
-      len = 1;
-      return E_BUFFER_NOT_FULL;
-    }
-
-    result = GetUIntLength(pReader, pos, len);
-
-    if (result < 0)  // error
-      return static_cast<long>(result);
-
-    if (result > 0)  // underflow
-      return E_BUFFER_NOT_FULL;
-
-    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > avail)
-      return E_BUFFER_NOT_FULL;
-
-    const long long size = ReadUInt(pReader, pos, len);
-
-    if (size < 0)  // error
-      return static_cast<long>(size);
-
-    pos += len;  // consume size field
-
-    // pos now points to start of payload
-
-    if ((cluster_stop >= 0) && (pos > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if (size == 0)  // weird
-      continue;
-
-    const long long unknown_size = (1LL << (7 * len)) - 1;
-
-    if (size == unknown_size)
-      return E_FILE_FORMAT_INVALID;  // not supported inside cluster
-
-    if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
-      return E_FILE_FORMAT_INVALID;
-
-    if (id == mkvmuxer::kMkvBlockGroup)
-      return 1;  // have at least one entry
-
-    if (id == mkvmuxer::kMkvSimpleBlock)
-      return 1;  // have at least one entry
-
-    pos += size;  // consume payload
-    if (cluster_stop >= 0 && pos > cluster_stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-}
-
-long long Cluster::GetTimeCode() const {
-  long long pos;
-  long len;
-
-  const long status = Load(pos, len);
-
-  if (status < 0)  // error
-    return status;
-
-  return m_timecode;
-}
-
-long long Cluster::GetTime() const {
-  const long long tc = GetTimeCode();
-
-  if (tc < 0)
-    return tc;
-
-  const SegmentInfo* const pInfo = m_pSegment->GetInfo();
-  assert(pInfo);
-
-  const long long scale = pInfo->GetTimeCodeScale();
-  assert(scale >= 1);
-
-  const long long t = m_timecode * scale;
-
-  return t;
-}
-
-long long Cluster::GetFirstTime() const {
-  const BlockEntry* pEntry;
-
-  const long status = GetFirst(pEntry);
-
-  if (status < 0)  // error
-    return status;
-
-  if (pEntry == NULL)  // empty cluster
-    return GetTime();
-
-  const Block* const pBlock = pEntry->GetBlock();
-  assert(pBlock);
-
-  return pBlock->GetTime(this);
-}
-
-long long Cluster::GetLastTime() const {
-  const BlockEntry* pEntry;
-
-  const long status = GetLast(pEntry);
-
-  if (status < 0)  // error
-    return status;
-
-  if (pEntry == NULL)  // empty cluster
-    return GetTime();
-
-  const Block* const pBlock = pEntry->GetBlock();
-  assert(pBlock);
-
-  return pBlock->GetTime(this);
-}
-
-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)
-    return E_PARSE_FAILED;
-
-  if (m_entries_count < 0) {  // haven't parsed anything yet
-    assert(m_entries == NULL);
-    assert(m_entries_size == 0);
-
-    m_entries_size = 1024;
-    m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
-    if (m_entries == NULL)
-      return -1;
-
-    m_entries_count = 0;
-  } else {
-    assert(m_entries);
-    assert(m_entries_size > 0);
-    assert(m_entries_count <= m_entries_size);
-
-    if (m_entries_count >= m_entries_size) {
-      const long entries_size = 2 * m_entries_size;
-
-      BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
-      if (entries == NULL)
-        return -1;
-
-      BlockEntry** src = m_entries;
-      BlockEntry** const src_end = src + m_entries_count;
-
-      BlockEntry** dst = entries;
-
-      while (src != src_end)
-        *dst++ = *src++;
-
-      delete[] m_entries;
-
-      m_entries = entries;
-      m_entries_size = entries_size;
-    }
-  }
-
-  if (id == mkvmuxer::kMkvBlockGroup)
-    return CreateBlockGroup(pos, size, discard_padding);
-  else
-    return CreateSimpleBlock(pos, size);
-}
-
-long Cluster::CreateBlockGroup(long long start_offset, long long size,
-                               long long discard_padding) {
-  assert(m_entries);
-  assert(m_entries_size > 0);
-  assert(m_entries_count >= 0);
-  assert(m_entries_count < m_entries_size);
-
-  IMkvReader* const pReader = m_pSegment->m_pReader;
-
-  long long pos = start_offset;
-  const long long stop = start_offset + size;
-
-  // For WebM files, there is a bias towards previous reference times
-  //(in order to support alt-ref frames, which refer back to the previous
-  // keyframe).  Normally a 0 value is not possible, but here we tenatively
-  // allow 0 as the value of a reference frame, with the interpretation
-  // that this is a "previous" reference time.
-
-  long long prev = 1;  // nonce
-  long long next = 0;  // nonce
-  long long duration = -1;  // really, this is unsigned
-
-  long long bpos = -1;
-  long long bsize = -1;
-
-  while (pos < stop) {
-    long len;
-    const long long id = ReadID(pReader, pos, len);
-    if (id < 0 || (pos + len) > stop)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume ID
-
-    const long long size = ReadUInt(pReader, pos, len);
-    assert(size >= 0);  // TODO
-    assert((pos + len) <= stop);
-
-    pos += len;  // consume size
-
-    if (id == mkvmuxer::kMkvBlock) {
-      if (bpos < 0) {  // Block ID
-        bpos = pos;
-        bsize = size;
-      }
-    } else if (id == mkvmuxer::kMkvBlockDuration) {
-      if (size > 8)
-        return E_FILE_FORMAT_INVALID;
-
-      duration = UnserializeUInt(pReader, pos, size);
-
-      if (duration < 0)
-        return E_FILE_FORMAT_INVALID;
-    } else if (id == mkvmuxer::kMkvReferenceBlock) {
-      if (size > 8 || size <= 0)
-        return E_FILE_FORMAT_INVALID;
-      const long size_ = static_cast<long>(size);
-
-      long long time;
-
-      long status = UnserializeInt(pReader, pos, size_, time);
-      assert(status == 0);
-      if (status != 0)
-        return -1;
-
-      if (time <= 0)  // see note above
-        prev = time;
-      else
-        next = time;
-    }
-
-    pos += size;  // consume payload
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-  if (bpos < 0)
-    return E_FILE_FORMAT_INVALID;
-
-  if (pos != stop)
-    return E_FILE_FORMAT_INVALID;
-  assert(bsize >= 0);
-
-  const long idx = m_entries_count;
-
-  BlockEntry** const ppEntry = m_entries + idx;
-  BlockEntry*& pEntry = *ppEntry;
-
-  pEntry = new (std::nothrow)
-      BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
-
-  if (pEntry == NULL)
-    return -1;  // generic error
-
-  BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
-
-  const long status = p->Parse();
-
-  if (status == 0) {  // success
-    ++m_entries_count;
-    return 0;
-  }
-
-  delete pEntry;
-  pEntry = 0;
-
-  return status;
-}
-
-long Cluster::CreateSimpleBlock(long long st, long long sz) {
-  assert(m_entries);
-  assert(m_entries_size > 0);
-  assert(m_entries_count >= 0);
-  assert(m_entries_count < m_entries_size);
-
-  const long idx = m_entries_count;
-
-  BlockEntry** const ppEntry = m_entries + idx;
-  BlockEntry*& pEntry = *ppEntry;
-
-  pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
-
-  if (pEntry == NULL)
-    return -1;  // generic error
-
-  SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
-
-  const long status = p->Parse();
-
-  if (status == 0) {
-    ++m_entries_count;
-    return 0;
-  }
-
-  delete pEntry;
-  pEntry = 0;
-
-  return status;
-}
-
-long Cluster::GetFirst(const BlockEntry*& pFirst) const {
-  if (m_entries_count <= 0) {
-    long long pos;
-    long len;
-
-    const long status = Parse(pos, len);
-
-    if (status < 0) {  // error
-      pFirst = NULL;
-      return status;
-    }
-
-    if (m_entries_count <= 0) {  // empty cluster
-      pFirst = NULL;
-      return 0;
-    }
-  }
-
-  assert(m_entries);
-
-  pFirst = m_entries[0];
-  assert(pFirst);
-
-  return 0;  // success
-}
-
-long Cluster::GetLast(const BlockEntry*& pLast) const {
-  for (;;) {
-    long long pos;
-    long len;
-
-    const long status = Parse(pos, len);
-
-    if (status < 0) {  // error
-      pLast = NULL;
-      return status;
-    }
-
-    if (status > 0)  // no new block
-      break;
-  }
-
-  if (m_entries_count <= 0) {
-    pLast = NULL;
-    return 0;
-  }
-
-  assert(m_entries);
-
-  const long idx = m_entries_count - 1;
-
-  pLast = m_entries[idx];
-  assert(pLast);
-
-  return 0;
-}
-
-long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
-  assert(pCurr);
-  assert(m_entries);
-  assert(m_entries_count > 0);
-
-  size_t idx = pCurr->GetIndex();
-  assert(idx < size_t(m_entries_count));
-  assert(m_entries[idx] == pCurr);
-
-  ++idx;
-
-  if (idx >= size_t(m_entries_count)) {
-    long long pos;
-    long len;
-
-    const long status = Parse(pos, len);
-
-    if (status < 0) {  // error
-      pNext = NULL;
-      return status;
-    }
-
-    if (status > 0) {
-      pNext = NULL;
-      return 0;
-    }
-
-    assert(m_entries);
-    assert(m_entries_count > 0);
-    assert(idx < size_t(m_entries_count));
-  }
-
-  pNext = m_entries[idx];
-  assert(pNext);
-
-  return 0;
-}
-
-long Cluster::GetEntryCount() const { return m_entries_count; }
-
-const BlockEntry* Cluster::GetEntry(const Track* pTrack,
-                                    long long time_ns) const {
-  assert(pTrack);
-
-  if (m_pSegment == NULL)  // this is the special EOS cluster
-    return pTrack->GetEOS();
-
-  const BlockEntry* pResult = pTrack->GetEOS();
-
-  long index = 0;
-
-  for (;;) {
-    if (index >= m_entries_count) {
-      long long pos;
-      long len;
-
-      const long status = Parse(pos, len);
-      assert(status >= 0);
-
-      if (status > 0)  // completely parsed, and no more entries
-        return pResult;
-
-      if (status < 0)  // should never happen
-        return 0;
-
-      assert(m_entries);
-      assert(index < m_entries_count);
-    }
-
-    const BlockEntry* const pEntry = m_entries[index];
-    assert(pEntry);
-    assert(!pEntry->EOS());
-
-    const Block* const pBlock = pEntry->GetBlock();
-    assert(pBlock);
-
-    if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
-      ++index;
-      continue;
-    }
-
-    if (pTrack->VetEntry(pEntry)) {
-      if (time_ns < 0)  // just want first candidate block
-        return pEntry;
-
-      const long long ns = pBlock->GetTime(this);
-
-      if (ns > time_ns)
-        return pResult;
-
-      pResult = pEntry;  // have a candidate
-    } else if (time_ns >= 0) {
-      const long long ns = pBlock->GetTime(this);
-
-      if (ns > time_ns)
-        return pResult;
-    }
-
-    ++index;
-  }
-}
-
-const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
-                                    const CuePoint::TrackPosition& tp) const {
-  assert(m_pSegment);
-  const long long tc = cp.GetTimeCode();
-
-  if (tp.m_block > 0) {
-    const long block = static_cast<long>(tp.m_block);
-    const long index = block - 1;
-
-    while (index >= m_entries_count) {
-      long long pos;
-      long len;
-
-      const long status = Parse(pos, len);
-
-      if (status < 0)  // TODO: can this happen?
-        return NULL;
-
-      if (status > 0)  // nothing remains to be parsed
-        return NULL;
-    }
-
-    const BlockEntry* const pEntry = m_entries[index];
-    assert(pEntry);
-    assert(!pEntry->EOS());
-
-    const Block* const pBlock = pEntry->GetBlock();
-    assert(pBlock);
-
-    if ((pBlock->GetTrackNumber() == tp.m_track) &&
-        (pBlock->GetTimeCode(this) == tc)) {
-      return pEntry;
-    }
-  }
-
-  long index = 0;
-
-  for (;;) {
-    if (index >= m_entries_count) {
-      long long pos;
-      long len;
-
-      const long status = Parse(pos, len);
-
-      if (status < 0)  // TODO: can this happen?
-        return NULL;
-
-      if (status > 0)  // nothing remains to be parsed
-        return NULL;
-
-      assert(m_entries);
-      assert(index < m_entries_count);
-    }
-
-    const BlockEntry* const pEntry = m_entries[index];
-    assert(pEntry);
-    assert(!pEntry->EOS());
-
-    const Block* const pBlock = pEntry->GetBlock();
-    assert(pBlock);
-
-    if (pBlock->GetTrackNumber() != tp.m_track) {
-      ++index;
-      continue;
-    }
-
-    const long long tc_ = pBlock->GetTimeCode(this);
-
-    if (tc_ < tc) {
-      ++index;
-      continue;
-    }
-
-    if (tc_ > tc)
-      return NULL;
-
-    const Tracks* const pTracks = m_pSegment->GetTracks();
-    assert(pTracks);
-
-    const long tn = static_cast<long>(tp.m_track);
-    const Track* const pTrack = pTracks->GetTrackByNumber(tn);
-
-    if (pTrack == NULL)
-      return NULL;
-
-    const long long type = pTrack->GetType();
-
-    if (type == 2)  // audio
-      return pEntry;
-
-    if (type != 1)  // not video
-      return NULL;
-
-    if (!pBlock->IsKey())
-      return NULL;
-
-    return pEntry;
-  }
-}
-
-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; }
-
-SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
-                         long long size)
-    : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
-
-long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
-BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
-const Block* SimpleBlock::GetBlock() const { return &m_block; }
-
-BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
-                       long long block_size, long long prev, long long next,
-                       long long duration, long long discard_padding)
-    : BlockEntry(pCluster, idx),
-      m_block(block_start, block_size, discard_padding),
-      m_prev(prev),
-      m_next(next),
-      m_duration(duration) {}
-
-long BlockGroup::Parse() {
-  const long status = m_block.Parse(m_pCluster);
-
-  if (status)
-    return status;
-
-  m_block.SetKey((m_prev > 0) && (m_next <= 0));
-
-  return 0;
-}
-
-BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
-const Block* BlockGroup::GetBlock() const { return &m_block; }
-long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
-long long BlockGroup::GetNextTimeCode() const { return m_next; }
-long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
-
-Block::Block(long long start, long long size_, long long discard_padding)
-    : m_start(start),
-      m_size(size_),
-      m_track(0),
-      m_timecode(-1),
-      m_flags(0),
-      m_frames(NULL),
-      m_frame_count(-1),
-      m_discard_padding(discard_padding) {}
-
-Block::~Block() { delete[] m_frames; }
-
-long Block::Parse(const Cluster* pCluster) {
-  if (pCluster == NULL)
-    return -1;
-
-  if (pCluster->m_pSegment == NULL)
-    return -1;
-
-  assert(m_start >= 0);
-  assert(m_size >= 0);
-  assert(m_track <= 0);
-  assert(m_frames == NULL);
-  assert(m_frame_count <= 0);
-
-  long long pos = m_start;
-  const long long stop = m_start + m_size;
-
-  long len;
-
-  IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
-
-  m_track = ReadUInt(pReader, pos, len);
-
-  if (m_track <= 0)
-    return E_FILE_FORMAT_INVALID;
-
-  if ((pos + len) > stop)
-    return E_FILE_FORMAT_INVALID;
-
-  pos += len;  // consume track number
-
-  if ((stop - pos) < 2)
-    return E_FILE_FORMAT_INVALID;
-
-  long status;
-  long long value;
-
-  status = UnserializeInt(pReader, pos, 2, value);
-
-  if (status)
-    return E_FILE_FORMAT_INVALID;
-
-  if (value < SHRT_MIN)
-    return E_FILE_FORMAT_INVALID;
-
-  if (value > SHRT_MAX)
-    return E_FILE_FORMAT_INVALID;
-
-  m_timecode = static_cast<short>(value);
-
-  pos += 2;
-
-  if ((stop - pos) <= 0)
-    return E_FILE_FORMAT_INVALID;
-
-  status = pReader->Read(pos, 1, &m_flags);
-
-  if (status)
-    return E_FILE_FORMAT_INVALID;
-
-  const int lacing = int(m_flags & 0x06) >> 1;
-
-  ++pos;  // consume flags byte
-
-  if (lacing == 0) {  // no lacing
-    if (pos > stop)
-      return E_FILE_FORMAT_INVALID;
-
-    m_frame_count = 1;
-    m_frames = new (std::nothrow) Frame[m_frame_count];
-    if (m_frames == NULL)
-      return -1;
-
-    Frame& f = m_frames[0];
-    f.pos = pos;
-
-    const long long frame_size = stop - pos;
-
-    if (frame_size > LONG_MAX || frame_size <= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    f.len = static_cast<long>(frame_size);
-
-    return 0;  // success
-  }
-
-  if (pos >= stop)
-    return E_FILE_FORMAT_INVALID;
-
-  unsigned char biased_count;
-
-  status = pReader->Read(pos, 1, &biased_count);
-
-  if (status)
-    return E_FILE_FORMAT_INVALID;
-
-  ++pos;  // consume frame count
-  if (pos > stop)
-    return E_FILE_FORMAT_INVALID;
-
-  m_frame_count = int(biased_count) + 1;
-
-  m_frames = new (std::nothrow) Frame[m_frame_count];
-  if (m_frames == NULL)
-    return -1;
-
-  if (!m_frames)
-    return E_FILE_FORMAT_INVALID;
-
-  if (lacing == 1) {  // Xiph
-    Frame* pf = m_frames;
-    Frame* const pf_end = pf + m_frame_count;
-
-    long long size = 0;
-    int frame_count = m_frame_count;
-
-    while (frame_count > 1) {
-      long frame_size = 0;
-
-      for (;;) {
-        unsigned char val;
-
-        if (pos >= stop)
-          return E_FILE_FORMAT_INVALID;
-
-        status = pReader->Read(pos, 1, &val);
-
-        if (status)
-          return E_FILE_FORMAT_INVALID;
-
-        ++pos;  // consume xiph size byte
-
-        frame_size += val;
-
-        if (val < 255)
-          break;
-      }
-
-      Frame& f = *pf++;
-      assert(pf < pf_end);
-      if (pf >= pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      f.pos = 0;  // patch later
-
-      if (frame_size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      f.len = frame_size;
-      size += frame_size;  // contribution of this frame
-
-      --frame_count;
-    }
-
-    if (pf >= pf_end || pos > stop)
-      return E_FILE_FORMAT_INVALID;
-
-    {
-      Frame& f = *pf++;
-
-      if (pf != pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      f.pos = 0;  // patch later
-
-      const long long total_size = stop - pos;
-
-      if (total_size < size)
-        return E_FILE_FORMAT_INVALID;
-
-      const long long frame_size = total_size - size;
-
-      if (frame_size > LONG_MAX || frame_size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      f.len = static_cast<long>(frame_size);
-    }
-
-    pf = m_frames;
-    while (pf != pf_end) {
-      Frame& f = *pf++;
-      assert((pos + f.len) <= stop);
-
-      if ((pos + f.len) > stop)
-        return E_FILE_FORMAT_INVALID;
-
-      f.pos = pos;
-      pos += f.len;
-    }
-
-    assert(pos == stop);
-    if (pos != stop)
-      return E_FILE_FORMAT_INVALID;
-
-  } else if (lacing == 2) {  // fixed-size lacing
-    if (pos >= stop)
-      return E_FILE_FORMAT_INVALID;
-
-    const long long total_size = stop - pos;
-
-    if ((total_size % m_frame_count) != 0)
-      return E_FILE_FORMAT_INVALID;
-
-    const long long frame_size = total_size / m_frame_count;
-
-    if (frame_size > LONG_MAX || frame_size <= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    Frame* pf = m_frames;
-    Frame* const pf_end = pf + m_frame_count;
-
-    while (pf != pf_end) {
-      assert((pos + frame_size) <= stop);
-      if ((pos + frame_size) > stop)
-        return E_FILE_FORMAT_INVALID;
-
-      Frame& f = *pf++;
-
-      f.pos = pos;
-      f.len = static_cast<long>(frame_size);
-
-      pos += frame_size;
-    }
-
-    assert(pos == stop);
-    if (pos != stop)
-      return E_FILE_FORMAT_INVALID;
-
-  } else {
-    assert(lacing == 3);  // EBML lacing
-
-    if (pos >= stop)
-      return E_FILE_FORMAT_INVALID;
-
-    long long size = 0;
-    int frame_count = m_frame_count;
-
-    long long frame_size = ReadUInt(pReader, pos, len);
-
-    if (frame_size <= 0)
-      return E_FILE_FORMAT_INVALID;
-
-    if (frame_size > LONG_MAX)
-      return E_FILE_FORMAT_INVALID;
-
-    if ((pos + len) > stop)
-      return E_FILE_FORMAT_INVALID;
-
-    pos += len;  // consume length of size of first frame
-
-    if ((pos + frame_size) > stop)
-      return E_FILE_FORMAT_INVALID;
-
-    Frame* pf = m_frames;
-    Frame* const pf_end = pf + m_frame_count;
-
-    {
-      Frame& curr = *pf;
-
-      curr.pos = 0;  // patch later
-
-      curr.len = static_cast<long>(frame_size);
-      size += curr.len;  // contribution of this frame
-    }
-
-    --frame_count;
-
-    while (frame_count > 1) {
-      if (pos >= stop)
-        return E_FILE_FORMAT_INVALID;
-
-      assert(pf < pf_end);
-      if (pf >= pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-
-      const Frame& prev = *pf++;
-      assert(prev.len == frame_size);
-      if (prev.len != frame_size)
-        return E_FILE_FORMAT_INVALID;
-
-      assert(pf < pf_end);
-      if (pf >= pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      Frame& curr = *pf;
-
-      curr.pos = 0;  // patch later
-
-      const long long delta_size_ = ReadUInt(pReader, pos, len);
-
-      if (delta_size_ < 0)
-        return E_FILE_FORMAT_INVALID;
-
-      if ((pos + len) > stop)
-        return E_FILE_FORMAT_INVALID;
-
-      pos += len;  // consume length of (delta) size
-      if (pos > stop)
-        return E_FILE_FORMAT_INVALID;
-
-      const int exp = 7 * len - 1;
-      const long long bias = (1LL << exp) - 1LL;
-      const long long delta_size = delta_size_ - bias;
-
-      frame_size += delta_size;
-
-      if (frame_size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      if (frame_size > LONG_MAX)
-        return E_FILE_FORMAT_INVALID;
-
-      curr.len = static_cast<long>(frame_size);
-      size += curr.len;  // contribution of this frame
-
-      --frame_count;
-    }
-
-    // parse last frame
-    if (frame_count > 0) {
-      if (pos > stop || pf >= pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      const Frame& prev = *pf++;
-      assert(prev.len == frame_size);
-      if (prev.len != frame_size)
-        return E_FILE_FORMAT_INVALID;
-
-      if (pf >= pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      Frame& curr = *pf++;
-      if (pf != pf_end)
-        return E_FILE_FORMAT_INVALID;
-
-      curr.pos = 0;  // patch later
-
-      const long long total_size = stop - pos;
-
-      if (total_size < size)
-        return E_FILE_FORMAT_INVALID;
-
-      frame_size = total_size - size;
-
-      if (frame_size > LONG_MAX || frame_size <= 0)
-        return E_FILE_FORMAT_INVALID;
-
-      curr.len = static_cast<long>(frame_size);
-    }
-
-    pf = m_frames;
-    while (pf != pf_end) {
-      Frame& f = *pf++;
-      assert((pos + f.len) <= stop);
-      if ((pos + f.len) > stop)
-        return E_FILE_FORMAT_INVALID;
-
-      f.pos = pos;
-      pos += f.len;
-    }
-
-    if (pos != stop)
-      return E_FILE_FORMAT_INVALID;
-  }
-
-  return 0;  // success
-}
-
-long long Block::GetTimeCode(const Cluster* pCluster) const {
-  if (pCluster == 0)
-    return m_timecode;
-
-  const long long tc0 = pCluster->GetTimeCode();
-  assert(tc0 >= 0);
-
-  const long long tc = tc0 + m_timecode;
-
-  return tc;  // unscaled timecode units
-}
-
-long long Block::GetTime(const Cluster* pCluster) const {
-  assert(pCluster);
-
-  const long long tc = GetTimeCode(pCluster);
-
-  const Segment* const pSegment = pCluster->m_pSegment;
-  const SegmentInfo* const pInfo = pSegment->GetInfo();
-  assert(pInfo);
-
-  const long long scale = pInfo->GetTimeCodeScale();
-  assert(scale >= 1);
-
-  const long long ns = tc * scale;
-
-  return ns;
-}
-
-long long Block::GetTrackNumber() const { return m_track; }
-
-bool Block::IsKey() const {
-  return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
-}
-
-void Block::SetKey(bool bKey) {
-  if (bKey)
-    m_flags |= static_cast<unsigned char>(1 << 7);
-  else
-    m_flags &= 0x7F;
-}
-
-bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
-
-Block::Lacing Block::GetLacing() const {
-  const int value = int(m_flags & 0x06) >> 1;
-  return static_cast<Lacing>(value);
-}
-
-int Block::GetFrameCount() const { return m_frame_count; }
-
-const Block::Frame& Block::GetFrame(int idx) const {
-  assert(idx >= 0);
-  assert(idx < m_frame_count);
-
-  const Frame& f = m_frames[idx];
-  assert(f.pos > 0);
-  assert(f.len > 0);
-
-  return f;
-}
-
-long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
-  assert(pReader);
-  assert(buf);
-
-  const long status = pReader->Read(pos, len, buf);
-  return status;
-}
-
-long long Block::GetDiscardPadding() const { return m_discard_padding; }
-
-}  // end namespace mkvparser
--- a/third_party/libwebm/mkvparser.hpp
+++ /dev/null
@@ -1,1025 +1,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 MKVPARSER_HPP
-#define MKVPARSER_HPP
-
-#include <cstddef>
-#include <cstdio>
-#include <cstdlib>
-
-namespace mkvparser {
-
-const int E_PARSE_FAILED = -1;
-const int E_FILE_FORMAT_INVALID = -2;
-const int E_BUFFER_NOT_FULL = -3;
-
-class IMkvReader {
- public:
-  virtual int Read(long long pos, long len, unsigned char* buf) = 0;
-  virtual int Length(long long* total, long long* available) = 0;
-
- protected:
-  virtual ~IMkvReader();
-};
-
-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);
-long long UnserializeUInt(IMkvReader*, long long pos, long long size);
-
-long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);
-long UnserializeInt(IMkvReader*, long long pos, long long size,
-                    long long& result);
-
-long UnserializeString(IMkvReader*, long long pos, long long size, char*& str);
-
-long ParseElementHeader(IMkvReader* pReader,
-                        long long& pos,  // consume id and size fields
-                        long long stop,  // if you know size of element's parent
-                        long long& id, long long& size);
-
-bool Match(IMkvReader*, long long&, unsigned long, long long&);
-bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
-
-void GetVersion(int& major, int& minor, int& build, int& revision);
-
-struct EBMLHeader {
-  EBMLHeader();
-  ~EBMLHeader();
-  long long m_version;
-  long long m_readVersion;
-  long long m_maxIdLength;
-  long long m_maxSizeLength;
-  char* m_docType;
-  long long m_docTypeVersion;
-  long long m_docTypeReadVersion;
-
-  long long Parse(IMkvReader*, long long&);
-  void Init();
-};
-
-class Segment;
-class Track;
-class Cluster;
-
-class Block {
-  Block(const Block&);
-  Block& operator=(const Block&);
-
- public:
-  const long long m_start;
-  const long long m_size;
-
-  Block(long long start, long long size, long long discard_padding);
-  ~Block();
-
-  long Parse(const Cluster*);
-
-  long long GetTrackNumber() const;
-  long long GetTimeCode(const Cluster*) const;  // absolute, but not scaled
-  long long GetTime(const Cluster*) const;  // absolute, and scaled (ns)
-  bool IsKey() const;
-  void SetKey(bool);
-  bool IsInvisible() const;
-
-  enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml };
-  Lacing GetLacing() const;
-
-  int GetFrameCount() const;  // to index frames: [0, count)
-
-  struct Frame {
-    long long pos;  // absolute offset
-    long len;
-
-    long Read(IMkvReader*, unsigned char*) const;
-  };
-
-  const Frame& GetFrame(int frame_index) const;
-
-  long long GetDiscardPadding() const;
-
- private:
-  long long m_track;  // Track::Number()
-  short m_timecode;  // relative to cluster
-  unsigned char m_flags;
-
-  Frame* m_frames;
-  int m_frame_count;
-
- protected:
-  const long long m_discard_padding;
-};
-
-class BlockEntry {
-  BlockEntry(const BlockEntry&);
-  BlockEntry& operator=(const BlockEntry&);
-
- protected:
-  BlockEntry(Cluster*, long index);
-
- public:
-  virtual ~BlockEntry();
-
-  bool EOS() const;
-  const Cluster* GetCluster() const;
-  long GetIndex() const;
-  virtual const Block* GetBlock() const = 0;
-
-  enum Kind { kBlockEOS, kBlockSimple, kBlockGroup };
-  virtual Kind GetKind() const = 0;
-
- protected:
-  Cluster* const m_pCluster;
-  const long m_index;
-};
-
-class SimpleBlock : public BlockEntry {
-  SimpleBlock(const SimpleBlock&);
-  SimpleBlock& operator=(const SimpleBlock&);
-
- public:
-  SimpleBlock(Cluster*, long index, long long start, long long size);
-  long Parse();
-
-  Kind GetKind() const;
-  const Block* GetBlock() const;
-
- protected:
-  Block m_block;
-};
-
-class BlockGroup : public BlockEntry {
-  BlockGroup(const BlockGroup&);
-  BlockGroup& operator=(const BlockGroup&);
-
- public:
-  BlockGroup(Cluster*, long index,
-             long long block_start,  // absolute pos of block's payload
-             long long block_size,  // size of block's payload
-             long long prev, long long next, long long duration,
-             long long discard_padding);
-
-  long Parse();
-
-  Kind GetKind() const;
-  const Block* GetBlock() const;
-
-  long long GetPrevTimeCode() const;  // relative to block's time
-  long long GetNextTimeCode() const;  // as above
-  long long GetDurationTimeCode() const;
-
- private:
-  Block m_block;
-  const long long m_prev;
-  const long long m_next;
-  const long long m_duration;
-};
-
-///////////////////////////////////////////////////////////////
-// ContentEncoding element
-// Elements used to describe if the track data has been encrypted or
-// compressed with zlib or header stripping.
-class ContentEncoding {
- public:
-  enum { kCTR = 1 };
-
-  ContentEncoding();
-  ~ContentEncoding();
-
-  // ContentCompression element names
-  struct ContentCompression {
-    ContentCompression();
-    ~ContentCompression();
-
-    unsigned long long algo;
-    unsigned char* settings;
-    long long settings_len;
-  };
-
-  // ContentEncAESSettings element names
-  struct ContentEncAESSettings {
-    ContentEncAESSettings() : cipher_mode(kCTR) {}
-    ~ContentEncAESSettings() {}
-
-    unsigned long long cipher_mode;
-  };
-
-  // ContentEncryption element names
-  struct ContentEncryption {
-    ContentEncryption();
-    ~ContentEncryption();
-
-    unsigned long long algo;
-    unsigned char* key_id;
-    long long key_id_len;
-    unsigned char* signature;
-    long long signature_len;
-    unsigned char* sig_key_id;
-    long long sig_key_id_len;
-    unsigned long long sig_algo;
-    unsigned long long sig_hash_algo;
-
-    ContentEncAESSettings aes_settings;
-  };
-
-  // Returns ContentCompression represented by |idx|. Returns NULL if |idx|
-  // is out of bounds.
-  const ContentCompression* GetCompressionByIndex(unsigned long idx) const;
-
-  // Returns number of ContentCompression elements in this ContentEncoding
-  // element.
-  unsigned long GetCompressionCount() const;
-
-  // Parses the ContentCompression element from |pReader|. |start| is the
-  // starting offset of the ContentCompression payload. |size| is the size in
-  // bytes of the ContentCompression payload. |compression| is where the parsed
-  // values will be stored.
-  long ParseCompressionEntry(long long start, long long size,
-                             IMkvReader* pReader,
-                             ContentCompression* compression);
-
-  // Returns ContentEncryption represented by |idx|. Returns NULL if |idx|
-  // is out of bounds.
-  const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const;
-
-  // Returns number of ContentEncryption elements in this ContentEncoding
-  // element.
-  unsigned long GetEncryptionCount() const;
-
-  // Parses the ContentEncAESSettings element from |pReader|. |start| is the
-  // starting offset of the ContentEncAESSettings payload. |size| is the
-  // size in bytes of the ContentEncAESSettings payload. |encryption| is
-  // where the parsed values will be stored.
-  long ParseContentEncAESSettingsEntry(long long start, long long size,
-                                       IMkvReader* pReader,
-                                       ContentEncAESSettings* aes);
-
-  // Parses the ContentEncoding element from |pReader|. |start| is the
-  // starting offset of the ContentEncoding payload. |size| is the size in
-  // bytes of the ContentEncoding payload. Returns true on success.
-  long ParseContentEncodingEntry(long long start, long long size,
-                                 IMkvReader* pReader);
-
-  // Parses the ContentEncryption element from |pReader|. |start| is the
-  // starting offset of the ContentEncryption payload. |size| is the size in
-  // bytes of the ContentEncryption payload. |encryption| is where the parsed
-  // values will be stored.
-  long ParseEncryptionEntry(long long start, long long size,
-                            IMkvReader* pReader, ContentEncryption* encryption);
-
-  unsigned long long encoding_order() const { return encoding_order_; }
-  unsigned long long encoding_scope() const { return encoding_scope_; }
-  unsigned long long encoding_type() const { return encoding_type_; }
-
- private:
-  // Member variables for list of ContentCompression elements.
-  ContentCompression** compression_entries_;
-  ContentCompression** compression_entries_end_;
-
-  // Member variables for list of ContentEncryption elements.
-  ContentEncryption** encryption_entries_;
-  ContentEncryption** encryption_entries_end_;
-
-  // ContentEncoding element names
-  unsigned long long encoding_order_;
-  unsigned long long encoding_scope_;
-  unsigned long long encoding_type_;
-
-  // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
-  ContentEncoding(const ContentEncoding&);
-  ContentEncoding& operator=(const ContentEncoding&);
-};
-
-class Track {
-  Track(const Track&);
-  Track& operator=(const Track&);
-
- public:
-  class Info;
-  static long Create(Segment*, const Info&, long long element_start,
-                     long long element_size, Track*&);
-
-  enum Type { kVideo = 1, kAudio = 2, kSubtitle = 0x11, kMetadata = 0x21 };
-
-  Segment* const m_pSegment;
-  const long long m_element_start;
-  const long long m_element_size;
-  virtual ~Track();
-
-  long GetType() const;
-  long GetNumber() const;
-  unsigned long long GetUid() const;
-  const char* GetNameAsUTF8() const;
-  const char* GetLanguage() const;
-  const char* GetCodecNameAsUTF8() const;
-  const char* GetCodecId() const;
-  const unsigned char* GetCodecPrivate(size_t&) const;
-  bool GetLacing() const;
-  unsigned long long GetDefaultDuration() const;
-  unsigned long long GetCodecDelay() const;
-  unsigned long long GetSeekPreRoll() const;
-
-  const BlockEntry* GetEOS() const;
-
-  struct Settings {
-    long long start;
-    long long size;
-  };
-
-  class Info {
-   public:
-    Info();
-    ~Info();
-    int Copy(Info&) const;
-    void Clear();
-    long type;
-    long number;
-    unsigned long long uid;
-    unsigned long long defaultDuration;
-    unsigned long long codecDelay;
-    unsigned long long seekPreRoll;
-    char* nameAsUTF8;
-    char* language;
-    char* codecId;
-    char* codecNameAsUTF8;
-    unsigned char* codecPrivate;
-    size_t codecPrivateSize;
-    bool lacing;
-    Settings settings;
-
-   private:
-    Info(const Info&);
-    Info& operator=(const Info&);
-    int CopyStr(char* Info::*str, Info&) const;
-  };
-
-  long GetFirst(const BlockEntry*&) const;
-  long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
-  virtual bool VetEntry(const BlockEntry*) const;
-  virtual long Seek(long long time_ns, const BlockEntry*&) const;
-
-  const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
-  unsigned long GetContentEncodingCount() const;
-
-  long ParseContentEncodingsEntry(long long start, long long size);
-
- protected:
-  Track(Segment*, long long element_start, long long element_size);
-
-  Info m_info;
-
-  class EOSBlock : public BlockEntry {
-   public:
-    EOSBlock();
-
-    Kind GetKind() const;
-    const Block* GetBlock() const;
-  };
-
-  EOSBlock m_eos;
-
- private:
-  ContentEncoding** content_encoding_entries_;
-  ContentEncoding** content_encoding_entries_end_;
-};
-
-class VideoTrack : public Track {
-  VideoTrack(const VideoTrack&);
-  VideoTrack& operator=(const VideoTrack&);
-
-  VideoTrack(Segment*, long long element_start, long long element_size);
-
- public:
-  static long Parse(Segment*, const Info&, long long element_start,
-                    long long element_size, VideoTrack*&);
-
-  long long GetWidth() const;
-  long long GetHeight() const;
-  long long GetDisplayWidth() const;
-  long long GetDisplayHeight() const;
-  long long GetDisplayUnit() const;
-  long long GetStereoMode() const;
-  double GetFrameRate() const;
-
-  bool VetEntry(const BlockEntry*) const;
-  long Seek(long long time_ns, const BlockEntry*&) const;
-
- private:
-  long long m_width;
-  long long m_height;
-  long long m_display_width;
-  long long m_display_height;
-  long long m_display_unit;
-  long long m_stereo_mode;
-
-  double m_rate;
-};
-
-class AudioTrack : public Track {
-  AudioTrack(const AudioTrack&);
-  AudioTrack& operator=(const AudioTrack&);
-
-  AudioTrack(Segment*, long long element_start, long long element_size);
-
- public:
-  static long Parse(Segment*, const Info&, long long element_start,
-                    long long element_size, AudioTrack*&);
-
-  double GetSamplingRate() const;
-  long long GetChannels() const;
-  long long GetBitDepth() const;
-
- private:
-  double m_rate;
-  long long m_channels;
-  long long m_bitDepth;
-};
-
-class Tracks {
-  Tracks(const Tracks&);
-  Tracks& operator=(const Tracks&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  Tracks(Segment*, long long start, long long size, long long element_start,
-         long long element_size);
-
-  ~Tracks();
-
-  long Parse();
-
-  unsigned long GetTracksCount() const;
-
-  const Track* GetTrackByNumber(long tn) const;
-  const Track* GetTrackByIndex(unsigned long idx) const;
-
- private:
-  Track** m_trackEntries;
-  Track** m_trackEntriesEnd;
-
-  long ParseTrackEntry(long long payload_start, long long payload_size,
-                       long long element_start, long long element_size,
-                       Track*&) const;
-};
-
-class Chapters {
-  Chapters(const Chapters&);
-  Chapters& operator=(const Chapters&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  Chapters(Segment*, long long payload_start, long long payload_size,
-           long long element_start, long long element_size);
-
-  ~Chapters();
-
-  long Parse();
-
-  class Atom;
-  class Edition;
-
-  class Display {
-    friend class Atom;
-    Display();
-    Display(const Display&);
-    ~Display();
-    Display& operator=(const Display&);
-
-   public:
-    const char* GetString() const;
-    const char* GetLanguage() const;
-    const char* GetCountry() const;
-
-   private:
-    void Init();
-    void ShallowCopy(Display&) const;
-    void Clear();
-    long Parse(IMkvReader*, long long pos, long long size);
-
-    char* m_string;
-    char* m_language;
-    char* m_country;
-  };
-
-  class Atom {
-    friend class Edition;
-    Atom();
-    Atom(const Atom&);
-    ~Atom();
-    Atom& operator=(const Atom&);
-
-   public:
-    unsigned long long GetUID() const;
-    const char* GetStringUID() const;
-
-    long long GetStartTimecode() const;
-    long long GetStopTimecode() const;
-
-    long long GetStartTime(const Chapters*) const;
-    long long GetStopTime(const Chapters*) const;
-
-    int GetDisplayCount() const;
-    const Display* GetDisplay(int index) const;
-
-   private:
-    void Init();
-    void ShallowCopy(Atom&) const;
-    void Clear();
-    long Parse(IMkvReader*, long long pos, long long size);
-    static long long GetTime(const Chapters*, long long timecode);
-
-    long ParseDisplay(IMkvReader*, long long pos, long long size);
-    bool ExpandDisplaysArray();
-
-    char* m_string_uid;
-    unsigned long long m_uid;
-    long long m_start_timecode;
-    long long m_stop_timecode;
-
-    Display* m_displays;
-    int m_displays_size;
-    int m_displays_count;
-  };
-
-  class Edition {
-    friend class Chapters;
-    Edition();
-    Edition(const Edition&);
-    ~Edition();
-    Edition& operator=(const Edition&);
-
-   public:
-    int GetAtomCount() const;
-    const Atom* GetAtom(int index) const;
-
-   private:
-    void Init();
-    void ShallowCopy(Edition&) const;
-    void Clear();
-    long Parse(IMkvReader*, long long pos, long long size);
-
-    long ParseAtom(IMkvReader*, long long pos, long long size);
-    bool ExpandAtomsArray();
-
-    Atom* m_atoms;
-    int m_atoms_size;
-    int m_atoms_count;
-  };
-
-  int GetEditionCount() const;
-  const Edition* GetEdition(int index) const;
-
- private:
-  long ParseEdition(long long pos, long long size);
-  bool ExpandEditionsArray();
-
-  Edition* m_editions;
-  int m_editions_size;
-  int m_editions_count;
-};
-
-class Tags {
-  Tags(const Tags&);
-  Tags& operator=(const Tags&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  Tags(Segment*, long long payload_start, long long payload_size,
-       long long element_start, long long element_size);
-
-  ~Tags();
-
-  long Parse();
-
-  class Tag;
-  class SimpleTag;
-
-  class SimpleTag {
-    friend class Tag;
-    SimpleTag();
-    SimpleTag(const SimpleTag&);
-    ~SimpleTag();
-    SimpleTag& operator=(const SimpleTag&);
-
-   public:
-    const char* GetTagName() const;
-    const char* GetTagString() const;
-
-   private:
-    void Init();
-    void ShallowCopy(SimpleTag&) const;
-    void Clear();
-    long Parse(IMkvReader*, long long pos, long long size);
-
-    char* m_tag_name;
-    char* m_tag_string;
-  };
-
-  class Tag {
-    friend class Tags;
-    Tag();
-    Tag(const Tag&);
-    ~Tag();
-    Tag& operator=(const Tag&);
-
-   public:
-    int GetSimpleTagCount() const;
-    const SimpleTag* GetSimpleTag(int index) const;
-
-   private:
-    void Init();
-    void ShallowCopy(Tag&) const;
-    void Clear();
-    long Parse(IMkvReader*, long long pos, long long size);
-
-    long ParseSimpleTag(IMkvReader*, long long pos, long long size);
-    bool ExpandSimpleTagsArray();
-
-    SimpleTag* m_simple_tags;
-    int m_simple_tags_size;
-    int m_simple_tags_count;
-  };
-
-  int GetTagCount() const;
-  const Tag* GetTag(int index) const;
-
- private:
-  long ParseTag(long long pos, long long size);
-  bool ExpandTagsArray();
-
-  Tag* m_tags;
-  int m_tags_size;
-  int m_tags_count;
-};
-
-class SegmentInfo {
-  SegmentInfo(const SegmentInfo&);
-  SegmentInfo& operator=(const SegmentInfo&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  SegmentInfo(Segment*, long long start, long long size,
-              long long element_start, long long element_size);
-
-  ~SegmentInfo();
-
-  long Parse();
-
-  long long GetTimeCodeScale() const;
-  long long GetDuration() const;  // scaled
-  const char* GetMuxingAppAsUTF8() const;
-  const char* GetWritingAppAsUTF8() const;
-  const char* GetTitleAsUTF8() const;
-
- private:
-  long long m_timecodeScale;
-  double m_duration;
-  char* m_pMuxingAppAsUTF8;
-  char* m_pWritingAppAsUTF8;
-  char* m_pTitleAsUTF8;
-};
-
-class SeekHead {
-  SeekHead(const SeekHead&);
-  SeekHead& operator=(const SeekHead&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  SeekHead(Segment*, long long start, long long size, long long element_start,
-           long long element_size);
-
-  ~SeekHead();
-
-  long Parse();
-
-  struct Entry {
-    // the SeekHead entry payload
-    long long id;
-    long long pos;
-
-    // absolute pos of SeekEntry ID
-    long long element_start;
-
-    // SeekEntry ID size + size size + payload
-    long long element_size;
-  };
-
-  int GetCount() const;
-  const Entry* GetEntry(int idx) const;
-
-  struct VoidElement {
-    // absolute pos of Void ID
-    long long element_start;
-
-    // ID size + size size + payload size
-    long long element_size;
-  };
-
-  int GetVoidElementCount() const;
-  const VoidElement* GetVoidElement(int idx) const;
-
- private:
-  Entry* m_entries;
-  int m_entry_count;
-
-  VoidElement* m_void_elements;
-  int m_void_element_count;
-
-  static bool ParseEntry(IMkvReader*,
-                         long long pos,  // payload
-                         long long size, Entry*);
-};
-
-class Cues;
-class CuePoint {
-  friend class Cues;
-
-  CuePoint(long, long long);
-  ~CuePoint();
-
-  CuePoint(const CuePoint&);
-  CuePoint& operator=(const CuePoint&);
-
- public:
-  long long m_element_start;
-  long long m_element_size;
-
-  bool Load(IMkvReader*);
-
-  long long GetTimeCode() const;  // absolute but unscaled
-  long long GetTime(const Segment*) const;  // absolute and scaled (ns units)
-
-  struct TrackPosition {
-    long long m_track;
-    long long m_pos;  // of cluster
-    long long m_block;
-    // codec_state  //defaults to 0
-    // reference = clusters containing req'd referenced blocks
-    //  reftime = timecode of the referenced block
-
-    bool Parse(IMkvReader*, long long, long long);
-  };
-
-  const TrackPosition* Find(const Track*) const;
-
- private:
-  const long m_index;
-  long long m_timecode;
-  TrackPosition* m_track_positions;
-  size_t m_track_positions_count;
-};
-
-class Cues {
-  friend class Segment;
-
-  Cues(Segment*, long long start, long long size, long long element_start,
-       long long element_size);
-  ~Cues();
-
-  Cues(const Cues&);
-  Cues& operator=(const Cues&);
-
- public:
-  Segment* const m_pSegment;
-  const long long m_start;
-  const long long m_size;
-  const long long m_element_start;
-  const long long m_element_size;
-
-  bool Find(  // lower bound of time_ns
-      long long time_ns, const Track*, const CuePoint*&,
-      const CuePoint::TrackPosition*&) const;
-
-  const CuePoint* GetFirst() const;
-  const CuePoint* GetLast() const;
-  const CuePoint* GetNext(const CuePoint*) const;
-
-  const BlockEntry* GetBlock(const CuePoint*,
-                             const CuePoint::TrackPosition*) const;
-
-  bool LoadCuePoint() const;
-  long GetCount() const;  // loaded only
-  // long GetTotal() const;  //loaded + preloaded
-  bool DoneParsing() const;
-
- private:
-  bool Init() const;
-  bool PreloadCuePoint(long&, long long) const;
-
-  mutable CuePoint** m_cue_points;
-  mutable long m_count;
-  mutable long m_preload_count;
-  mutable long long m_pos;
-};
-
-class Cluster {
-  friend class Segment;
-
-  Cluster(const Cluster&);
-  Cluster& operator=(const Cluster&);
-
- public:
-  Segment* const m_pSegment;
-
- public:
-  static Cluster* Create(Segment*,
-                         long index,  // index in segment
-                         long long off);  // offset relative to segment
-  // long long element_size);
-
-  Cluster();  // EndOfStream
-  ~Cluster();
-
-  bool EOS() const;
-
-  long long GetTimeCode() const;  // absolute, but not scaled
-  long long GetTime() const;  // absolute, and scaled (nanosecond units)
-  long long GetFirstTime() const;  // time (ns) of first (earliest) block
-  long long GetLastTime() const;  // time (ns) of last (latest) block
-
-  long GetFirst(const BlockEntry*&) const;
-  long GetLast(const BlockEntry*&) const;
-  long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
-
-  const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
-  const BlockEntry* GetEntry(const CuePoint&,
-                             const CuePoint::TrackPosition&) const;
-  // const BlockEntry* GetMaxKey(const VideoTrack*) const;
-
-  //    static bool HasBlockEntries(const Segment*, long long);
-
-  static long HasBlockEntries(const Segment*, long long idoff, long long& pos,
-                              long& size);
-
-  long GetEntryCount() const;
-
-  long Load(long long& pos, long& size) const;
-
-  long Parse(long long& pos, long& size) const;
-  long GetEntry(long index, const mkvparser::BlockEntry*&) const;
-
- protected:
-  Cluster(Segment*, long index, long long element_start);
-  // long long element_size);
-
- public:
-  const long long m_element_start;
-  long long GetPosition() const;  // offset relative to segment
-
-  long GetIndex() const;
-  long long GetElementSize() const;
-  // long long GetPayloadSize() const;
-
-  // long long Unparsed() const;
-
- private:
-  long m_index;
-  mutable long long m_pos;
-  // mutable long long m_size;
-  mutable long long m_element_size;
-  mutable long long m_timecode;
-  mutable BlockEntry** m_entries;
-  mutable long m_entries_size;
-  mutable long m_entries_count;
-
-  long ParseSimpleBlock(long long, long long&, long&);
-  long ParseBlockGroup(long long, long long&, long&);
-
-  long CreateBlock(long long id, long long pos, long long size,
-                   long long discard_padding);
-  long CreateBlockGroup(long long start_offset, long long size,
-                        long long discard_padding);
-  long CreateSimpleBlock(long long, long long);
-};
-
-class Segment {
-  friend class Cues;
-  friend class Track;
-  friend class VideoTrack;
-
-  Segment(const Segment&);
-  Segment& operator=(const Segment&);
-
- private:
-  Segment(IMkvReader*, long long elem_start,
-          // long long elem_size,
-          long long pos, long long size);
-
- public:
-  IMkvReader* const m_pReader;
-  const long long m_element_start;
-  // const long long m_element_size;
-  const long long m_start;  // posn of segment payload
-  const long long m_size;  // size of segment payload
-  Cluster m_eos;  // TODO: make private?
-
-  static long long CreateInstance(IMkvReader*, long long, Segment*&);
-  ~Segment();
-
-  long Load();  // loads headers and all clusters
-
-  // for incremental loading
-  // long long Unparsed() const;
-  bool DoneParsing() const;
-  long long ParseHeaders();  // stops when first cluster is found
-  // long FindNextCluster(long long& pos, long& size) const;
-  long LoadCluster(long long& pos, long& size);  // load one cluster
-  long LoadCluster();
-
-  long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos,
-                 long& size);
-
-  const SeekHead* GetSeekHead() const;
-  const Tracks* GetTracks() const;
-  const SegmentInfo* GetInfo() const;
-  const Cues* GetCues() const;
-  const Chapters* GetChapters() const;
-  const Tags* GetTags() const;
-
-  long long GetDuration() const;
-
-  unsigned long GetCount() const;
-  const Cluster* GetFirst() const;
-  const Cluster* GetLast() const;
-  const Cluster* GetNext(const Cluster*);
-
-  const Cluster* FindCluster(long long time_nanoseconds) const;
-  // const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
-
-  const Cluster* FindOrPreloadCluster(long long pos);
-
-  long ParseCues(long long cues_off,  // offset relative to start of segment
-                 long long& parse_pos, long& parse_len);
-
- private:
-  long long m_pos;  // absolute file posn; what has been consumed so far
-  Cluster* m_pUnknownSize;
-
-  SeekHead* m_pSeekHead;
-  SegmentInfo* m_pInfo;
-  Tracks* m_pTracks;
-  Cues* m_pCues;
-  Chapters* m_pChapters;
-  Tags* m_pTags;
-  Cluster** m_clusters;
-  long m_clusterCount;  // number of entries for which m_index >= 0
-  long m_clusterPreloadCount;  // number of entries for which m_index < 0
-  long m_clusterSize;  // array size
-
-  long DoLoadCluster(long long&, long&);
-  long DoLoadClusterUnknownSize(long long&, long&);
-  long DoParseNext(const Cluster*&, long long&, long&);
-
-  bool AppendCluster(Cluster*);
-  bool PreloadCluster(Cluster*, ptrdiff_t);
-
-  // void ParseSeekHead(long long pos, long long size);
-  // void ParseSeekEntry(long long pos, long long size);
-  // void ParseCues(long long);
-
-  const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
-};
-
-}  // end namespace mkvparser
-
-inline long mkvparser::Segment::LoadCluster() {
-  long long pos;
-  long size;
-
-  return LoadCluster(pos, size);
-}
-
-#endif  // MKVPARSER_HPP
--- /dev/null
+++ b/third_party/libwebm/mkvparser/mkvparser.cc
@@ -1,0 +1,7940 @@
+// 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 "mkvparser/mkvparser.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#include <float.h>  // _isnan() / _finite()
+#define MSC_COMPAT
+#endif
+
+#include <cassert>
+#include <cfloat>
+#include <climits>
+#include <cmath>
+#include <cstring>
+#include <memory>
+#include <new>
+
+#include "common/webmids.h"
+
+namespace mkvparser {
+const float MasteringMetadata::kValueNotPresent = FLT_MAX;
+const long long Colour::kValueNotPresent = LLONG_MAX;
+
+#ifdef MSC_COMPAT
+inline bool isnan(double val) { return !!_isnan(val); }
+inline bool isinf(double val) { return !_finite(val); }
+#else
+inline bool isnan(double val) { return std::isnan(val); }
+inline bool isinf(double val) { return std::isinf(val); }
+#endif  // MSC_COMPAT
+
+IMkvReader::~IMkvReader() {}
+
+template <typename Type>
+Type* SafeArrayAlloc(unsigned long long num_elements,
+                     unsigned long long element_size) {
+  if (num_elements == 0 || element_size == 0)
+    return NULL;
+
+  const size_t kMaxAllocSize = 0x80000000;  // 2GiB
+  const unsigned long long num_bytes = num_elements * element_size;
+  if (element_size > (kMaxAllocSize / num_elements))
+    return NULL;
+  if (num_bytes != static_cast<size_t>(num_bytes))
+    return NULL;
+
+  return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
+}
+
+void GetVersion(int& major, int& minor, int& build, int& revision) {
+  major = 1;
+  minor = 0;
+  build = 0;
+  revision = 30;
+}
+
+long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
+  if (!pReader || pos < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  len = 1;
+  unsigned char b;
+  int status = pReader->Read(pos, 1, &b);
+
+  if (status < 0)  // error or underflow
+    return status;
+
+  if (status > 0)  // interpreted as "underflow"
+    return E_BUFFER_NOT_FULL;
+
+  if (b == 0)  // we can't handle u-int values larger than 8 bytes
+    return E_FILE_FORMAT_INVALID;
+
+  unsigned char m = 0x80;
+
+  while (!(b & m)) {
+    m >>= 1;
+    ++len;
+  }
+
+  long long result = b & (~m);
+  ++pos;
+
+  for (int i = 1; i < len; ++i) {
+    status = pReader->Read(pos, 1, &b);
+
+    if (status < 0) {
+      len = 1;
+      return status;
+    }
+
+    if (status > 0) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result <<= 8;
+    result |= b;
+
+    ++pos;
+  }
+
+  return result;
+}
+
+// Reads an EBML ID and returns it.
+// An ID must at least 1 byte long, cannot exceed 4, and its value must be
+// greater than 0.
+// See known EBML values and EBMLMaxIDLength:
+// http://www.matroska.org/technical/specs/index.html
+// Returns the ID, or a value less than 0 to report an error while reading the
+// ID.
+long long ReadID(IMkvReader* pReader, long long pos, long& len) {
+  if (pReader == NULL || pos < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  // Read the first byte. The length in bytes of the ID is determined by
+  // finding the first set bit in the first byte of the ID.
+  unsigned char temp_byte = 0;
+  int read_status = pReader->Read(pos, 1, &temp_byte);
+
+  if (read_status < 0)
+    return E_FILE_FORMAT_INVALID;
+  else if (read_status > 0)  // No data to read.
+    return E_BUFFER_NOT_FULL;
+
+  if (temp_byte == 0)  // ID length > 8 bytes; invalid file.
+    return E_FILE_FORMAT_INVALID;
+
+  int bit_pos = 0;
+  const int kMaxIdLengthInBytes = 4;
+  const int kCheckByte = 0x80;
+
+  // Find the first bit that's set.
+  bool found_bit = false;
+  for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
+    if ((kCheckByte >> bit_pos) & temp_byte) {
+      found_bit = true;
+      break;
+    }
+  }
+
+  if (!found_bit) {
+    // The value is too large to be a valid ID.
+    return E_FILE_FORMAT_INVALID;
+  }
+
+  // Read the remaining bytes of the ID (if any).
+  const int id_length = bit_pos + 1;
+  long long ebml_id = temp_byte;
+  for (int i = 1; i < id_length; ++i) {
+    ebml_id <<= 8;
+    read_status = pReader->Read(pos + i, 1, &temp_byte);
+
+    if (read_status < 0)
+      return E_FILE_FORMAT_INVALID;
+    else if (read_status > 0)
+      return E_BUFFER_NOT_FULL;
+
+    ebml_id |= temp_byte;
+  }
+
+  len = id_length;
+  return ebml_id;
+}
+
+long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
+  if (!pReader || pos < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  long long total, available;
+
+  int status = pReader->Length(&total, &available);
+  if (status < 0 || (total >= 0 && available > total))
+    return E_FILE_FORMAT_INVALID;
+
+  len = 1;
+
+  if (pos >= available)
+    return pos;  // too few bytes available
+
+  unsigned char b;
+
+  status = pReader->Read(pos, 1, &b);
+
+  if (status != 0)
+    return status;
+
+  if (b == 0)  // we can't handle u-int values larger than 8 bytes
+    return E_FILE_FORMAT_INVALID;
+
+  unsigned char m = 0x80;
+
+  while (!(b & m)) {
+    m >>= 1;
+    ++len;
+  }
+
+  return 0;  // success
+}
+
+// TODO(vigneshv): This function assumes that unsigned values never have their
+// high bit set.
+long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
+  if (!pReader || pos < 0 || (size <= 0) || (size > 8))
+    return E_FILE_FORMAT_INVALID;
+
+  long long result = 0;
+
+  for (long long i = 0; i < size; ++i) {
+    unsigned char b;
+
+    const long status = pReader->Read(pos, 1, &b);
+
+    if (status < 0)
+      return status;
+
+    result <<= 8;
+    result |= b;
+
+    ++pos;
+  }
+
+  return result;
+}
+
+long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
+                      double& result) {
+  if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
+    return E_FILE_FORMAT_INVALID;
+
+  const long size = static_cast<long>(size_);
+
+  unsigned char buf[8];
+
+  const int status = pReader->Read(pos, size, buf);
+
+  if (status < 0)  // error
+    return status;
+
+  if (size == 4) {
+    union {
+      float f;
+      unsigned long ff;
+    };
+
+    ff = 0;
+
+    for (int i = 0;;) {
+      ff |= buf[i];
+
+      if (++i >= 4)
+        break;
+
+      ff <<= 8;
+    }
+
+    result = f;
+  } else {
+    union {
+      double d;
+      unsigned long long dd;
+    };
+
+    dd = 0;
+
+    for (int i = 0;;) {
+      dd |= buf[i];
+
+      if (++i >= 8)
+        break;
+
+      dd <<= 8;
+    }
+
+    result = d;
+  }
+
+  if (mkvparser::isinf(result) || mkvparser::isnan(result))
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
+                    long long& result_ref) {
+  if (!pReader || pos < 0 || size < 1 || size > 8)
+    return E_FILE_FORMAT_INVALID;
+
+  signed char first_byte = 0;
+  const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
+
+  if (status < 0)
+    return status;
+
+  unsigned long long result = first_byte;
+  ++pos;
+
+  for (long i = 1; i < size; ++i) {
+    unsigned char b;
+
+    const long status = pReader->Read(pos, 1, &b);
+
+    if (status < 0)
+      return status;
+
+    result <<= 8;
+    result |= b;
+
+    ++pos;
+  }
+
+  result_ref = static_cast<long long>(result);
+  return 0;
+}
+
+long UnserializeString(IMkvReader* pReader, long long pos, long long size,
+                       char*& str) {
+  delete[] str;
+  str = NULL;
+
+  if (size >= LONG_MAX || size < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  // +1 for '\0' terminator
+  const long required_size = static_cast<long>(size) + 1;
+
+  str = SafeArrayAlloc<char>(1, required_size);
+  if (str == NULL)
+    return E_FILE_FORMAT_INVALID;
+
+  unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
+
+  const long status = pReader->Read(pos, static_cast<long>(size), buf);
+
+  if (status) {
+    delete[] str;
+    str = NULL;
+
+    return status;
+  }
+
+  str[required_size - 1] = '\0';
+  return 0;
+}
+
+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;
+
+  long len;
+
+  id = ReadID(pReader, pos, len);
+
+  if (id < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume id
+
+  if (stop >= 0 && pos >= stop)
+    return E_FILE_FORMAT_INVALID;
+
+  size = ReadUInt(pReader, pos, len);
+
+  if (size < 0 || len < 1 || len > 8) {
+    // Invalid: Negative payload size, negative or 0 length integer, or integer
+    // larger than 64 bits (libwebm cannot handle them).
+    return E_FILE_FORMAT_INVALID;
+  }
+
+  // Avoid rolling over pos when very close to LLONG_MAX.
+  const unsigned long long rollover_check =
+      static_cast<unsigned long long>(pos) + len;
+  if (rollover_check > LLONG_MAX)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume length of size
+
+  // pos now designates payload
+
+  if (stop >= 0 && pos > stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;  // success
+}
+
+bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
+           long long& val) {
+  if (!pReader || pos < 0)
+    return false;
+
+  long long total = 0;
+  long long available = 0;
+
+  const long status = pReader->Length(&total, &available);
+  if (status < 0 || (total >= 0 && available > total))
+    return false;
+
+  long len = 0;
+
+  const long long id = ReadID(pReader, pos, len);
+  if (id < 0 || (available - pos) > len)
+    return false;
+
+  if (static_cast<unsigned long>(id) != expected_id)
+    return false;
+
+  pos += len;  // consume id
+
+  const long long size = ReadUInt(pReader, pos, len);
+  if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
+    return false;
+
+  pos += len;  // consume length of size of payload
+
+  val = UnserializeUInt(pReader, pos, size);
+  if (val < 0)
+    return false;
+
+  pos += size;  // consume size of payload
+
+  return true;
+}
+
+bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
+           unsigned char*& buf, size_t& buflen) {
+  if (!pReader || pos < 0)
+    return false;
+
+  long long total = 0;
+  long long available = 0;
+
+  long status = pReader->Length(&total, &available);
+  if (status < 0 || (total >= 0 && available > total))
+    return false;
+
+  long len = 0;
+  const long long id = ReadID(pReader, pos, len);
+  if (id < 0 || (available - pos) > len)
+    return false;
+
+  if (static_cast<unsigned long>(id) != expected_id)
+    return false;
+
+  pos += len;  // consume id
+
+  const long long size = ReadUInt(pReader, pos, len);
+  if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
+    return false;
+
+  unsigned long long rollover_check =
+      static_cast<unsigned long long>(pos) + len;
+  if (rollover_check > LLONG_MAX)
+    return false;
+
+  pos += len;  // consume length of size of payload
+
+  rollover_check = static_cast<unsigned long long>(pos) + size;
+  if (rollover_check > LLONG_MAX)
+    return false;
+
+  if ((pos + size) > available)
+    return false;
+
+  if (size >= LONG_MAX)
+    return false;
+
+  const long buflen_ = static_cast<long>(size);
+
+  buf = SafeArrayAlloc<unsigned char>(1, buflen_);
+  if (!buf)
+    return false;
+
+  status = pReader->Read(pos, buflen_, buf);
+  if (status != 0)
+    return false;
+
+  buflen = buflen_;
+
+  pos += size;  // consume size of payload
+  return true;
+}
+
+EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
+
+EBMLHeader::~EBMLHeader() { delete[] m_docType; }
+
+void EBMLHeader::Init() {
+  m_version = 1;
+  m_readVersion = 1;
+  m_maxIdLength = 4;
+  m_maxSizeLength = 8;
+
+  if (m_docType) {
+    delete[] m_docType;
+    m_docType = NULL;
+  }
+
+  m_docTypeVersion = 1;
+  m_docTypeReadVersion = 1;
+}
+
+long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
+  if (!pReader)
+    return E_FILE_FORMAT_INVALID;
+
+  long long total, available;
+
+  long status = pReader->Length(&total, &available);
+
+  if (status < 0)  // error
+    return status;
+
+  pos = 0;
+
+  // Scan until we find what looks like the first byte of the EBML header.
+  const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
+  const unsigned char kEbmlByte0 = 0x1A;
+  unsigned char scan_byte = 0;
+
+  while (pos < kMaxScanBytes) {
+    status = pReader->Read(pos, 1, &scan_byte);
+
+    if (status < 0)  // error
+      return status;
+    else if (status > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if (scan_byte == kEbmlByte0)
+      break;
+
+    ++pos;
+  }
+
+  long len = 0;
+  const long long ebml_id = ReadID(pReader, pos, len);
+
+  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.
+  pos += 4;
+
+  // Read length of size field.
+  long long result = GetUIntLength(pReader, pos, len);
+
+  if (result < 0)  // error
+    return E_FILE_FORMAT_INVALID;
+  else if (result > 0)  // need more data
+    return E_BUFFER_NOT_FULL;
+
+  if (len < 1 || len > 8)
+    return E_FILE_FORMAT_INVALID;
+
+  if ((total >= 0) && ((total - pos) < len))
+    return E_FILE_FORMAT_INVALID;
+
+  if ((available - pos) < len)
+    return pos + len;  // try again later
+
+  // Read the EBML header size.
+  result = ReadUInt(pReader, pos, len);
+
+  if (result < 0)  // error
+    return result;
+
+  pos += len;  // consume size field
+
+  // pos now designates start of payload
+
+  if ((total >= 0) && ((total - pos) < result))
+    return E_FILE_FORMAT_INVALID;
+
+  if ((available - pos) < result)
+    return pos + result;
+
+  const long long end = pos + result;
+
+  Init();
+
+  while (pos < end) {
+    long long id, size;
+
+    status = ParseElementHeader(pReader, pos, end, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (id == libwebm::kMkvEBMLVersion) {
+      m_version = UnserializeUInt(pReader, pos, size);
+
+      if (m_version <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvEBMLReadVersion) {
+      m_readVersion = UnserializeUInt(pReader, pos, size);
+
+      if (m_readVersion <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvEBMLMaxIDLength) {
+      m_maxIdLength = UnserializeUInt(pReader, pos, size);
+
+      if (m_maxIdLength <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvEBMLMaxSizeLength) {
+      m_maxSizeLength = UnserializeUInt(pReader, pos, size);
+
+      if (m_maxSizeLength <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDocType) {
+      if (m_docType)
+        return E_FILE_FORMAT_INVALID;
+
+      status = UnserializeString(pReader, pos, size, m_docType);
+
+      if (status)  // error
+        return status;
+    } else if (id == libwebm::kMkvDocTypeVersion) {
+      m_docTypeVersion = UnserializeUInt(pReader, pos, size);
+
+      if (m_docTypeVersion <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDocTypeReadVersion) {
+      m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
+
+      if (m_docTypeReadVersion <= 0)
+        return E_FILE_FORMAT_INVALID;
+    }
+
+    pos += size;
+  }
+
+  if (pos != end)
+    return E_FILE_FORMAT_INVALID;
+
+  // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
+  if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
+    return E_FILE_FORMAT_INVALID;
+
+  // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
+  if (m_maxIdLength <= 0 || m_maxIdLength > 4 || m_maxSizeLength <= 0 ||
+      m_maxSizeLength > 8)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+Segment::Segment(IMkvReader* pReader, long long elem_start,
+                 // long long elem_size,
+                 long long start, long long size)
+    : m_pReader(pReader),
+      m_element_start(elem_start),
+      // m_element_size(elem_size),
+      m_start(start),
+      m_size(size),
+      m_pos(start),
+      m_pUnknownSize(0),
+      m_pSeekHead(NULL),
+      m_pInfo(NULL),
+      m_pTracks(NULL),
+      m_pCues(NULL),
+      m_pChapters(NULL),
+      m_pTags(NULL),
+      m_clusters(NULL),
+      m_clusterCount(0),
+      m_clusterPreloadCount(0),
+      m_clusterSize(0) {}
+
+Segment::~Segment() {
+  const long count = m_clusterCount + m_clusterPreloadCount;
+
+  Cluster** i = m_clusters;
+  Cluster** j = m_clusters + count;
+
+  while (i != j) {
+    Cluster* const p = *i++;
+    delete p;
+  }
+
+  delete[] m_clusters;
+
+  delete m_pTracks;
+  delete m_pInfo;
+  delete m_pCues;
+  delete m_pChapters;
+  delete m_pTags;
+  delete m_pSeekHead;
+}
+
+long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
+                                  Segment*& pSegment) {
+  if (pReader == NULL || pos < 0)
+    return E_PARSE_FAILED;
+
+  pSegment = NULL;
+
+  long long total, available;
+
+  const long status = pReader->Length(&total, &available);
+
+  if (status < 0)  // error
+    return status;
+
+  if (available < 0)
+    return -1;
+
+  if ((total >= 0) && (available > total))
+    return -1;
+
+  // I would assume that in practice this loop would execute
+  // exactly once, but we allow for other elements (e.g. Void)
+  // to immediately follow the EBML header.  This is fine for
+  // the source filter case (since the entire file is available),
+  // but in the splitter case over a network we should probably
+  // just give up early.  We could for example decide only to
+  // execute this loop a maximum of, say, 10 times.
+  // TODO:
+  // There is an implied "give up early" by only parsing up
+  // to the available limit.  We do do that, but only if the
+  // total file size is unknown.  We could decide to always
+  // use what's available as our limit (irrespective of whether
+  // we happen to know the total file length).  This would have
+  // as its sense "parse this much of the file before giving up",
+  // which a slightly different sense from "try to parse up to
+  // 10 EMBL elements before giving up".
+
+  for (;;) {
+    if ((total >= 0) && (pos >= total))
+      return E_FILE_FORMAT_INVALID;
+
+    // Read ID
+    long len;
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result)  // error, or too few available bytes
+      return result;
+
+    if ((total >= 0) && ((pos + len) > total))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > available)
+      return pos + len;
+
+    const long long idpos = pos;
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume ID
+
+    // Read Size
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result)  // error, or too few available bytes
+      return result;
+
+    if ((total >= 0) && ((pos + len) > total))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > available)
+      return pos + len;
+
+    long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return size;
+
+    pos += len;  // consume length of size of element
+
+    // Pos now points to start of payload
+
+    // Handle "unknown size" for live streaming of webm files.
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (id == libwebm::kMkvSegment) {
+      if (size == unknown_size)
+        size = -1;
+
+      else if (total < 0)
+        size = -1;
+
+      else if ((pos + size) > total)
+        size = -1;
+
+      pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
+      if (pSegment == NULL)
+        return E_PARSE_FAILED;
+
+      return 0;  // success
+    }
+
+    if (size == unknown_size)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((total >= 0) && ((pos + size) > total))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + size) > available)
+      return pos + size;
+
+    pos += size;  // consume payload
+  }
+}
+
+long long Segment::ParseHeaders() {
+  // Outermost (level 0) segment object has been constructed,
+  // and pos designates start of payload.  We need to find the
+  // inner (level 1) elements.
+  long long total, available;
+
+  const int status = m_pReader->Length(&total, &available);
+
+  if (status < 0)  // error
+    return status;
+
+  if (total > 0 && available > total)
+    return E_FILE_FORMAT_INVALID;
+
+  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
+
+  if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
+      (segment_stop >= 0 && m_pos > segment_stop)) {
+    return E_FILE_FORMAT_INVALID;
+  }
+
+  for (;;) {
+    if ((total >= 0) && (m_pos >= total))
+      break;
+
+    if ((segment_stop >= 0) && (m_pos >= segment_stop))
+      break;
+
+    long long pos = m_pos;
+    const long long element_start = pos;
+
+    // Avoid rolling over pos when very close to LLONG_MAX.
+    unsigned long long rollover_check = pos + 1ULL;
+    if (rollover_check > LLONG_MAX)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + 1) > available)
+      return (pos + 1);
+
+    long len;
+    long long result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return result;
+
+    if (result > 0) {
+      // MkvReader doesn't have enough data to satisfy this read attempt.
+      return (pos + 1);
+    }
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > available)
+      return pos + len;
+
+    const long long idpos = pos;
+    const long long id = ReadID(m_pReader, idpos, len);
+
+    if (id < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (id == libwebm::kMkvCluster)
+      break;
+
+    pos += len;  // consume ID
+
+    if ((pos + 1) > available)
+      return (pos + 1);
+
+    // Read Size
+    result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return result;
+
+    if (result > 0) {
+      // MkvReader doesn't have enough data to satisfy this read attempt.
+      return (pos + 1);
+    }
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > available)
+      return pos + len;
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+
+    if (size < 0 || len < 1 || len > 8) {
+      // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
+      // len > 8 is true instead of checking this _everywhere_.
+      return size;
+    }
+
+    pos += len;  // consume length of size of element
+
+    // Avoid rolling over pos when very close to LLONG_MAX.
+    rollover_check = static_cast<unsigned long long>(pos) + size;
+    if (rollover_check > LLONG_MAX)
+      return E_FILE_FORMAT_INVALID;
+
+    const long long element_size = size + pos - element_start;
+
+    // Pos now points to start of payload
+
+    if ((segment_stop >= 0) && ((pos + size) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    // We read EBML elements either in total or nothing at all.
+
+    if ((pos + size) > available)
+      return pos + size;
+
+    if (id == libwebm::kMkvInfo) {
+      if (m_pInfo)
+        return E_FILE_FORMAT_INVALID;
+
+      m_pInfo = new (std::nothrow)
+          SegmentInfo(this, pos, size, element_start, element_size);
+
+      if (m_pInfo == NULL)
+        return -1;
+
+      const long status = m_pInfo->Parse();
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvTracks) {
+      if (m_pTracks)
+        return E_FILE_FORMAT_INVALID;
+
+      m_pTracks = new (std::nothrow)
+          Tracks(this, pos, size, element_start, element_size);
+
+      if (m_pTracks == NULL)
+        return -1;
+
+      const long status = m_pTracks->Parse();
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvCues) {
+      if (m_pCues == NULL) {
+        m_pCues = new (std::nothrow)
+            Cues(this, pos, size, element_start, element_size);
+
+        if (m_pCues == NULL)
+          return -1;
+      }
+    } else if (id == libwebm::kMkvSeekHead) {
+      if (m_pSeekHead == NULL) {
+        m_pSeekHead = new (std::nothrow)
+            SeekHead(this, pos, size, element_start, element_size);
+
+        if (m_pSeekHead == NULL)
+          return -1;
+
+        const long status = m_pSeekHead->Parse();
+
+        if (status)
+          return status;
+      }
+    } else if (id == libwebm::kMkvChapters) {
+      if (m_pChapters == NULL) {
+        m_pChapters = new (std::nothrow)
+            Chapters(this, pos, size, element_start, element_size);
+
+        if (m_pChapters == NULL)
+          return -1;
+
+        const long status = m_pChapters->Parse();
+
+        if (status)
+          return status;
+      }
+    } else if (id == libwebm::kMkvTags) {
+      if (m_pTags == NULL) {
+        m_pTags = new (std::nothrow)
+            Tags(this, pos, size, element_start, element_size);
+
+        if (m_pTags == NULL)
+          return -1;
+
+        const long status = m_pTags->Parse();
+
+        if (status)
+          return status;
+      }
+    }
+
+    m_pos = pos + size;  // consume payload
+  }
+
+  if (segment_stop >= 0 && m_pos > segment_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if (m_pInfo == NULL)  // TODO: liberalize this behavior
+    return E_FILE_FORMAT_INVALID;
+
+  if (m_pTracks == NULL)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;  // success
+}
+
+long Segment::LoadCluster(long long& pos, long& len) {
+  for (;;) {
+    const long result = DoLoadCluster(pos, len);
+
+    if (result <= 1)
+      return result;
+  }
+}
+
+long Segment::DoLoadCluster(long long& pos, long& len) {
+  if (m_pos < 0)
+    return DoLoadClusterUnknownSize(pos, len);
+
+  long long total, avail;
+
+  long status = m_pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  if (total >= 0 && avail > total)
+    return E_FILE_FORMAT_INVALID;
+
+  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
+
+  long long cluster_off = -1;  // offset relative to start of segment
+  long long cluster_size = -1;  // size of cluster payload
+
+  for (;;) {
+    if ((total >= 0) && (m_pos >= total))
+      return 1;  // no more clusters
+
+    if ((segment_stop >= 0) && (m_pos >= segment_stop))
+      return 1;  // no more clusters
+
+    pos = m_pos;
+
+    // Read ID
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long idpos = pos;
+    const long long id = ReadID(m_pReader, idpos, len);
+
+    if (id < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume ID
+
+    // Read Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    pos += len;  // consume length of size of element
+
+    // pos now points to start of payload
+
+    if (size == 0) {
+      // Missing element payload: move on.
+      m_pos = pos;
+      continue;
+    }
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if ((segment_stop >= 0) && (size != unknown_size) &&
+        ((pos + size) > segment_stop)) {
+      return E_FILE_FORMAT_INVALID;
+    }
+
+    if (id == libwebm::kMkvCues) {
+      if (size == unknown_size) {
+        // Cues element of unknown size: Not supported.
+        return E_FILE_FORMAT_INVALID;
+      }
+
+      if (m_pCues == NULL) {
+        const long long element_size = (pos - idpos) + size;
+
+        m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
+        if (m_pCues == NULL)
+          return -1;
+      }
+
+      m_pos = pos + size;  // consume payload
+      continue;
+    }
+
+    if (id != libwebm::kMkvCluster) {
+      // Besides the Segment, Libwebm allows only cluster elements of unknown
+      // size. Fail the parse upon encountering a non-cluster element reporting
+      // unknown size.
+      if (size == unknown_size)
+        return E_FILE_FORMAT_INVALID;
+
+      m_pos = pos + size;  // consume payload
+      continue;
+    }
+
+    // We have a cluster.
+
+    cluster_off = idpos - m_start;  // relative pos
+
+    if (size != unknown_size)
+      cluster_size = size;
+
+    break;
+  }
+
+  if (cluster_off < 0) {
+    // No cluster, die.
+    return E_FILE_FORMAT_INVALID;
+  }
+
+  long long pos_;
+  long len_;
+
+  status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
+
+  if (status < 0) {  // error, or underflow
+    pos = pos_;
+    len = len_;
+
+    return status;
+  }
+
+  // status == 0 means "no block entries found"
+  // status > 0 means "found at least one block entry"
+
+  // TODO:
+  // The issue here is that the segment increments its own
+  // pos ptr past the most recent cluster parsed, and then
+  // starts from there to parse the next cluster.  If we
+  // don't know the size of the current cluster, then we
+  // must either parse its payload (as we do below), looking
+  // for the cluster (or cues) ID to terminate the parse.
+  // This isn't really what we want: rather, we really need
+  // a way to create the curr cluster object immediately.
+  // The pity is that cluster::parse can determine its own
+  // boundary, and we largely duplicate that same logic here.
+  //
+  // Maybe we need to get rid of our look-ahead preloading
+  // in source::parse???
+  //
+  // As we're parsing the blocks in the curr cluster
+  //(in cluster::parse), we should have some way to signal
+  // to the segment that we have determined the boundary,
+  // so it can adjust its own segment::m_pos member.
+  //
+  // The problem is that we're asserting in asyncreadinit,
+  // because we adjust the pos down to the curr seek pos,
+  // and the resulting adjusted len is > 2GB.  I'm suspicious
+  // that this is even correct, but even if it is, we can't
+  // be loading that much data in the cache anyway.
+
+  const long idx = m_clusterCount;
+
+  if (m_clusterPreloadCount > 0) {
+    if (idx >= m_clusterSize)
+      return E_FILE_FORMAT_INVALID;
+
+    Cluster* const pCluster = m_clusters[idx];
+    if (pCluster == NULL || pCluster->m_index >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    const long long off = pCluster->GetPosition();
+    if (off < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (off == cluster_off) {  // preloaded already
+      if (status == 0)  // no entries found
+        return E_FILE_FORMAT_INVALID;
+
+      if (cluster_size >= 0)
+        pos += cluster_size;
+      else {
+        const long long element_size = pCluster->GetElementSize();
+
+        if (element_size <= 0)
+          return E_FILE_FORMAT_INVALID;  // TODO: handle this case
+
+        pos = pCluster->m_element_start + element_size;
+      }
+
+      pCluster->m_index = idx;  // move from preloaded to loaded
+      ++m_clusterCount;
+      --m_clusterPreloadCount;
+
+      m_pos = pos;  // consume payload
+      if (segment_stop >= 0 && m_pos > segment_stop)
+        return E_FILE_FORMAT_INVALID;
+
+      return 0;  // success
+    }
+  }
+
+  if (status == 0) {  // no entries found
+    if (cluster_size >= 0)
+      pos += cluster_size;
+
+    if ((total >= 0) && (pos >= total)) {
+      m_pos = total;
+      return 1;  // no more clusters
+    }
+
+    if ((segment_stop >= 0) && (pos >= segment_stop)) {
+      m_pos = segment_stop;
+      return 1;  // no more clusters
+    }
+
+    m_pos = pos;
+    return 2;  // try again
+  }
+
+  // status > 0 means we have an entry
+
+  Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
+  if (pCluster == NULL)
+    return -1;
+
+  if (!AppendCluster(pCluster)) {
+    delete pCluster;
+    return -1;
+  }
+
+  if (cluster_size >= 0) {
+    pos += cluster_size;
+
+    m_pos = pos;
+
+    if (segment_stop > 0 && m_pos > segment_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    return 0;
+  }
+
+  m_pUnknownSize = pCluster;
+  m_pos = -pos;
+
+  return 0;  // partial success, since we have a new cluster
+
+  // status == 0 means "no block entries found"
+  // pos designates start of payload
+  // m_pos has NOT been adjusted yet (in case we need to come back here)
+}
+
+long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
+  if (m_pos >= 0 || m_pUnknownSize == NULL)
+    return E_PARSE_FAILED;
+
+  const long status = m_pUnknownSize->Parse(pos, len);
+
+  if (status < 0)  // error or underflow
+    return status;
+
+  if (status == 0)  // parsed a block
+    return 2;  // continue parsing
+
+  const long long start = m_pUnknownSize->m_element_start;
+  const long long size = m_pUnknownSize->GetElementSize();
+
+  if (size < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  pos = start + size;
+  m_pos = pos;
+
+  m_pUnknownSize = 0;
+
+  return 2;  // continue parsing
+}
+
+bool Segment::AppendCluster(Cluster* pCluster) {
+  if (pCluster == NULL || pCluster->m_index < 0)
+    return false;
+
+  const long count = m_clusterCount + m_clusterPreloadCount;
+
+  long& size = m_clusterSize;
+  const long idx = pCluster->m_index;
+
+  if (size < count || idx != m_clusterCount)
+    return false;
+
+  if (count >= size) {
+    const long n = (size <= 0) ? 2048 : 2 * size;
+
+    Cluster** const qq = new (std::nothrow) Cluster*[n];
+    if (qq == NULL)
+      return false;
+
+    Cluster** q = qq;
+    Cluster** p = m_clusters;
+    Cluster** const pp = p + count;
+
+    while (p != pp)
+      *q++ = *p++;
+
+    delete[] m_clusters;
+
+    m_clusters = qq;
+    size = n;
+  }
+
+  if (m_clusterPreloadCount > 0) {
+    Cluster** const p = m_clusters + m_clusterCount;
+    if (*p == NULL || (*p)->m_index >= 0)
+      return false;
+
+    Cluster** q = p + m_clusterPreloadCount;
+    if (q >= (m_clusters + size))
+      return false;
+
+    for (;;) {
+      Cluster** const qq = q - 1;
+      if ((*qq)->m_index >= 0)
+        return false;
+
+      *q = *qq;
+      q = qq;
+
+      if (q == p)
+        break;
+    }
+  }
+
+  m_clusters[idx] = pCluster;
+  ++m_clusterCount;
+  return true;
+}
+
+bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
+  if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
+    return false;
+
+  const long count = m_clusterCount + m_clusterPreloadCount;
+
+  long& size = m_clusterSize;
+  if (size < count)
+    return false;
+
+  if (count >= size) {
+    const long n = (size <= 0) ? 2048 : 2 * size;
+
+    Cluster** const qq = new (std::nothrow) Cluster*[n];
+    if (qq == NULL)
+      return false;
+    Cluster** q = qq;
+
+    Cluster** p = m_clusters;
+    Cluster** const pp = p + count;
+
+    while (p != pp)
+      *q++ = *p++;
+
+    delete[] m_clusters;
+
+    m_clusters = qq;
+    size = n;
+  }
+
+  if (m_clusters == NULL)
+    return false;
+
+  Cluster** const p = m_clusters + idx;
+
+  Cluster** q = m_clusters + count;
+  if (q < p || q >= (m_clusters + size))
+    return false;
+
+  while (q > p) {
+    Cluster** const qq = q - 1;
+
+    if ((*qq)->m_index >= 0)
+      return false;
+
+    *q = *qq;
+    q = qq;
+  }
+
+  m_clusters[idx] = pCluster;
+  ++m_clusterPreloadCount;
+  return true;
+}
+
+long Segment::Load() {
+  if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
+    return E_PARSE_FAILED;
+
+  // Outermost (level 0) segment object has been constructed,
+  // and pos designates start of payload.  We need to find the
+  // inner (level 1) elements.
+
+  const long long header_status = ParseHeaders();
+
+  if (header_status < 0)  // error
+    return static_cast<long>(header_status);
+
+  if (header_status > 0)  // underflow
+    return E_BUFFER_NOT_FULL;
+
+  if (m_pInfo == NULL || m_pTracks == NULL)
+    return E_FILE_FORMAT_INVALID;
+
+  for (;;) {
+    const int status = LoadCluster();
+
+    if (status < 0)  // error
+      return status;
+
+    if (status >= 1)  // no more clusters
+      return 0;
+  }
+}
+
+SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
+                   long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_start(start),
+      m_size(size_),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_entries(0),
+      m_entry_count(0),
+      m_void_elements(0),
+      m_void_element_count(0) {}
+
+SeekHead::~SeekHead() {
+  delete[] m_entries;
+  delete[] m_void_elements;
+}
+
+long SeekHead::Parse() {
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = m_start;
+  const long long stop = m_start + m_size;
+
+  // first count the seek head entries
+
+  int entry_count = 0;
+  int void_element_count = 0;
+
+  while (pos < stop) {
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvSeek)
+      ++entry_count;
+    else if (id == libwebm::kMkvVoid)
+      ++void_element_count;
+
+    pos += size;  // consume payload
+
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  m_entries = new (std::nothrow) Entry[entry_count];
+
+  if (m_entries == NULL)
+    return -1;
+
+  m_void_elements = new (std::nothrow) VoidElement[void_element_count];
+
+  if (m_void_elements == NULL)
+    return -1;
+
+  // now parse the entries and void elements
+
+  Entry* pEntry = m_entries;
+  VoidElement* pVoidElement = m_void_elements;
+
+  pos = m_start;
+
+  while (pos < stop) {
+    const long long idpos = pos;
+
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    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 == libwebm::kMkvVoid) {
+      VoidElement& e = *pVoidElement++;
+
+      e.element_start = idpos;
+      e.element_size = (pos + size) - idpos;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
+  assert(count_ >= 0);
+  assert(count_ <= entry_count);
+
+  m_entry_count = static_cast<int>(count_);
+
+  count_ = ptrdiff_t(pVoidElement - m_void_elements);
+  assert(count_ >= 0);
+  assert(count_ <= void_element_count);
+
+  m_void_element_count = static_cast<int>(count_);
+
+  return 0;
+}
+
+int SeekHead::GetCount() const { return m_entry_count; }
+
+const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
+  if (idx < 0)
+    return 0;
+
+  if (idx >= m_entry_count)
+    return 0;
+
+  return m_entries + idx;
+}
+
+int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
+
+const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
+  if (idx < 0)
+    return 0;
+
+  if (idx >= m_void_element_count)
+    return 0;
+
+  return m_void_elements + idx;
+}
+
+long Segment::ParseCues(long long off, long long& pos, long& len) {
+  if (m_pCues)
+    return 0;  // success
+
+  if (off < 0)
+    return -1;
+
+  long long total, avail;
+
+  const int status = m_pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  pos = m_start + off;
+
+  if ((total < 0) || (pos >= total))
+    return 1;  // don't bother parsing cues
+
+  const long long element_start = pos;
+  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  long long result = GetUIntLength(m_pReader, pos, len);
+
+  if (result < 0)  // error
+    return static_cast<long>(result);
+
+  if (result > 0)  // underflow (weird)
+  {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + len) > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long idpos = pos;
+
+  const long long id = ReadID(m_pReader, idpos, len);
+
+  if (id != libwebm::kMkvCues)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume ID
+  assert((segment_stop < 0) || (pos <= segment_stop));
+
+  // Read Size
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  result = GetUIntLength(m_pReader, pos, len);
+
+  if (result < 0)  // error
+    return static_cast<long>(result);
+
+  if (result > 0)  // underflow (weird)
+  {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + len) > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long size = ReadUInt(m_pReader, pos, len);
+
+  if (size < 0)  // error
+    return static_cast<long>(size);
+
+  if (size == 0)  // weird, although technically not illegal
+    return 1;  // done
+
+  pos += len;  // consume length of size of element
+  assert((segment_stop < 0) || (pos <= segment_stop));
+
+  // Pos now points to start of payload
+
+  const long long element_stop = pos + size;
+
+  if ((segment_stop >= 0) && (element_stop > segment_stop))
+    return E_FILE_FORMAT_INVALID;
+
+  if ((total >= 0) && (element_stop > total))
+    return 1;  // don't bother parsing anymore
+
+  len = static_cast<long>(size);
+
+  if (element_stop > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long element_size = element_stop - element_start;
+
+  m_pCues =
+      new (std::nothrow) Cues(this, pos, size, element_start, element_size);
+  if (m_pCues == NULL)
+    return -1;
+
+  return 0;  // success
+}
+
+bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
+                          Entry* pEntry) {
+  if (size_ <= 0)
+    return false;
+
+  long long pos = start;
+  const long long stop = start + size_;
+
+  long len;
+
+  // parse the container for the level-1 element ID
+
+  const long long seekIdId = ReadID(pReader, pos, len);
+  if (seekIdId < 0)
+    return false;
+
+  if (seekIdId != libwebm::kMkvSeekID)
+    return false;
+
+  if ((pos + len) > stop)
+    return false;
+
+  pos += len;  // consume SeekID id
+
+  const long long seekIdSize = ReadUInt(pReader, pos, len);
+
+  if (seekIdSize <= 0)
+    return false;
+
+  if ((pos + len) > stop)
+    return false;
+
+  pos += len;  // consume size of field
+
+  if ((pos + seekIdSize) > stop)
+    return false;
+
+  // Note that the SeekId payload really is serialized
+  // as a "Matroska integer", not as a plain binary value.
+  // In fact, Matroska requires that ID values in the
+  // stream exactly match the binary representation as listed
+  // in the Matroska specification.
+  //
+  // This parser is more liberal, and permits IDs to have
+  // any width.  (This could make the representation in the stream
+  // different from what's in the spec, but it doesn't matter here,
+  // since we always normalize "Matroska integer" values.)
+
+  pEntry->id = ReadUInt(pReader, pos, len);  // payload
+
+  if (pEntry->id <= 0)
+    return false;
+
+  if (len != seekIdSize)
+    return false;
+
+  pos += seekIdSize;  // consume SeekID payload
+
+  const long long seekPosId = ReadID(pReader, pos, len);
+
+  if (seekPosId != libwebm::kMkvSeekPosition)
+    return false;
+
+  if ((pos + len) > stop)
+    return false;
+
+  pos += len;  // consume id
+
+  const long long seekPosSize = ReadUInt(pReader, pos, len);
+
+  if (seekPosSize <= 0)
+    return false;
+
+  if ((pos + len) > stop)
+    return false;
+
+  pos += len;  // consume size
+
+  if ((pos + seekPosSize) > stop)
+    return false;
+
+  pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
+
+  if (pEntry->pos < 0)
+    return false;
+
+  pos += seekPosSize;  // consume payload
+
+  if (pos != stop)
+    return false;
+
+  return true;
+}
+
+Cues::Cues(Segment* pSegment, long long start_, long long size_,
+           long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_start(start_),
+      m_size(size_),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_cue_points(NULL),
+      m_count(0),
+      m_preload_count(0),
+      m_pos(start_) {}
+
+Cues::~Cues() {
+  const long n = m_count + m_preload_count;
+
+  CuePoint** p = m_cue_points;
+  CuePoint** const q = p + n;
+
+  while (p != q) {
+    CuePoint* const pCP = *p++;
+    assert(pCP);
+
+    delete pCP;
+  }
+
+  delete[] m_cue_points;
+}
+
+long Cues::GetCount() const {
+  if (m_cue_points == NULL)
+    return -1;
+
+  return m_count;  // TODO: really ignore preload count?
+}
+
+bool Cues::DoneParsing() const {
+  const long long stop = m_start + m_size;
+  return (m_pos >= stop);
+}
+
+bool Cues::Init() const {
+  if (m_cue_points)
+    return true;
+
+  if (m_count != 0 || m_preload_count != 0)
+    return false;
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  const long long stop = m_start + m_size;
+  long long pos = m_start;
+
+  long cue_points_size = 0;
+
+  while (pos < stop) {
+    const long long idpos = pos;
+
+    long len;
+
+    const long long id = ReadID(pReader, pos, len);
+    if (id < 0 || (pos + len) > stop) {
+      return false;
+    }
+
+    pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos, len);
+    if (size < 0 || (pos + len > stop)) {
+      return false;
+    }
+
+    pos += len;  // consume Size field
+    if (pos + size > stop) {
+      return false;
+    }
+
+    if (id == libwebm::kMkvCuePoint) {
+      if (!PreloadCuePoint(cue_points_size, idpos))
+        return false;
+    }
+
+    pos += size;  // skip payload
+  }
+  return true;
+}
+
+bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
+  if (m_count != 0)
+    return false;
+
+  if (m_preload_count >= cue_points_size) {
+    const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
+
+    CuePoint** const qq = new (std::nothrow) CuePoint*[n];
+    if (qq == NULL)
+      return false;
+
+    CuePoint** q = qq;  // beginning of target
+
+    CuePoint** p = m_cue_points;  // beginning of source
+    CuePoint** const pp = p + m_preload_count;  // end of source
+
+    while (p != pp)
+      *q++ = *p++;
+
+    delete[] m_cue_points;
+
+    m_cue_points = qq;
+    cue_points_size = n;
+  }
+
+  CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
+  if (pCP == NULL)
+    return false;
+
+  m_cue_points[m_preload_count++] = pCP;
+  return true;
+}
+
+bool Cues::LoadCuePoint() const {
+  const long long stop = m_start + m_size;
+
+  if (m_pos >= stop)
+    return false;  // nothing else to do
+
+  if (!Init()) {
+    m_pos = stop;
+    return false;
+  }
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  while (m_pos < stop) {
+    const long long idpos = m_pos;
+
+    long len;
+
+    const long long id = ReadID(pReader, m_pos, len);
+    if (id < 0 || (m_pos + len) > stop)
+      return false;
+
+    m_pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, m_pos, len);
+    if (size < 0 || (m_pos + len) > stop)
+      return false;
+
+    m_pos += len;  // consume Size field
+    if ((m_pos + size) > stop)
+      return false;
+
+    if (id != libwebm::kMkvCuePoint) {
+      m_pos += size;  // consume payload
+      if (m_pos > stop)
+        return false;
+
+      continue;
+    }
+
+    if (m_preload_count < 1)
+      return false;
+
+    CuePoint* const pCP = m_cue_points[m_count];
+    if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
+      return false;
+
+    if (!pCP->Load(pReader)) {
+      m_pos = stop;
+      return false;
+    }
+    ++m_count;
+    --m_preload_count;
+
+    m_pos += size;  // consume payload
+    if (m_pos > stop)
+      return false;
+
+    return true;  // yes, we loaded a cue point
+  }
+
+  return false;  // no, we did not load a cue point
+}
+
+bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
+                const CuePoint::TrackPosition*& pTP) const {
+  if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
+    return false;
+
+  CuePoint** const ii = m_cue_points;
+  CuePoint** i = ii;
+
+  CuePoint** const jj = ii + m_count;
+  CuePoint** j = jj;
+
+  pCP = *i;
+  if (pCP == NULL)
+    return false;
+
+  if (time_ns <= pCP->GetTime(m_pSegment)) {
+    pTP = pCP->Find(pTrack);
+    return (pTP != NULL);
+  }
+
+  while (i < j) {
+    // INVARIANT:
+    //[ii, i) <= time_ns
+    //[i, j)  ?
+    //[j, jj) > time_ns
+
+    CuePoint** const k = i + (j - i) / 2;
+    if (k >= jj)
+      return false;
+
+    CuePoint* const pCP = *k;
+    if (pCP == NULL)
+      return false;
+
+    const long long t = pCP->GetTime(m_pSegment);
+
+    if (t <= time_ns)
+      i = k + 1;
+    else
+      j = k;
+
+    if (i > j)
+      return false;
+  }
+
+  if (i != j || i > jj || i <= ii)
+    return false;
+
+  pCP = *--i;
+
+  if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
+    return false;
+
+  // TODO: here and elsewhere, it's probably not correct to search
+  // for the cue point with this time, and then search for a matching
+  // track.  In principle, the matching track could be on some earlier
+  // cue point, and with our current algorithm, we'd miss it.  To make
+  // this bullet-proof, we'd need to create a secondary structure,
+  // with a list of cue points that apply to a track, and then search
+  // that track-based structure for a matching cue point.
+
+  pTP = pCP->Find(pTrack);
+  return (pTP != NULL);
+}
+
+const CuePoint* Cues::GetFirst() const {
+  if (m_cue_points == NULL || m_count == 0)
+    return NULL;
+
+  CuePoint* const* const pp = m_cue_points;
+  if (pp == NULL)
+    return NULL;
+
+  CuePoint* const pCP = pp[0];
+  if (pCP == NULL || pCP->GetTimeCode() < 0)
+    return NULL;
+
+  return pCP;
+}
+
+const CuePoint* Cues::GetLast() const {
+  if (m_cue_points == NULL || m_count <= 0)
+    return NULL;
+
+  const long index = m_count - 1;
+
+  CuePoint* const* const pp = m_cue_points;
+  if (pp == NULL)
+    return NULL;
+
+  CuePoint* const pCP = pp[index];
+  if (pCP == NULL || pCP->GetTimeCode() < 0)
+    return NULL;
+
+  return pCP;
+}
+
+const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
+  if (pCurr == NULL || pCurr->GetTimeCode() < 0 || m_cue_points == NULL ||
+      m_count < 1) {
+    return NULL;
+  }
+
+  long index = pCurr->m_index;
+  if (index >= m_count)
+    return NULL;
+
+  CuePoint* const* const pp = m_cue_points;
+  if (pp == NULL || pp[index] != pCurr)
+    return NULL;
+
+  ++index;
+
+  if (index >= m_count)
+    return NULL;
+
+  CuePoint* const pNext = pp[index];
+
+  if (pNext == NULL || pNext->GetTimeCode() < 0)
+    return NULL;
+
+  return pNext;
+}
+
+const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
+                                 const CuePoint::TrackPosition* pTP) const {
+  if (pCP == NULL || pTP == NULL)
+    return NULL;
+
+  return m_pSegment->GetBlock(*pCP, *pTP);
+}
+
+const BlockEntry* Segment::GetBlock(const CuePoint& cp,
+                                    const CuePoint::TrackPosition& tp) {
+  Cluster** const ii = m_clusters;
+  Cluster** i = ii;
+
+  const long count = m_clusterCount + m_clusterPreloadCount;
+
+  Cluster** const jj = ii + count;
+  Cluster** j = jj;
+
+  while (i < j) {
+    // INVARIANT:
+    //[ii, i) < pTP->m_pos
+    //[i, j) ?
+    //[j, jj)  > pTP->m_pos
+
+    Cluster** const k = i + (j - i) / 2;
+    assert(k < jj);
+
+    Cluster* const pCluster = *k;
+    assert(pCluster);
+
+    // const long long pos_ = pCluster->m_pos;
+    // assert(pos_);
+    // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
+
+    const long long pos = pCluster->GetPosition();
+    assert(pos >= 0);
+
+    if (pos < tp.m_pos)
+      i = k + 1;
+    else if (pos > tp.m_pos)
+      j = k;
+    else
+      return pCluster->GetEntry(cp, tp);
+  }
+
+  assert(i == j);
+  // assert(Cluster::HasBlockEntries(this, tp.m_pos));
+
+  Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos);  //, -1);
+  if (pCluster == NULL)
+    return NULL;
+
+  const ptrdiff_t idx = i - m_clusters;
+
+  if (!PreloadCluster(pCluster, idx)) {
+    delete pCluster;
+    return NULL;
+  }
+  assert(m_clusters);
+  assert(m_clusterPreloadCount > 0);
+  assert(m_clusters[idx] == pCluster);
+
+  return pCluster->GetEntry(cp, tp);
+}
+
+const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
+  if (requested_pos < 0)
+    return 0;
+
+  Cluster** const ii = m_clusters;
+  Cluster** i = ii;
+
+  const long count = m_clusterCount + m_clusterPreloadCount;
+
+  Cluster** const jj = ii + count;
+  Cluster** j = jj;
+
+  while (i < j) {
+    // INVARIANT:
+    //[ii, i) < pTP->m_pos
+    //[i, j) ?
+    //[j, jj)  > pTP->m_pos
+
+    Cluster** const k = i + (j - i) / 2;
+    assert(k < jj);
+
+    Cluster* const pCluster = *k;
+    assert(pCluster);
+
+    // const long long pos_ = pCluster->m_pos;
+    // assert(pos_);
+    // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
+
+    const long long pos = pCluster->GetPosition();
+    assert(pos >= 0);
+
+    if (pos < requested_pos)
+      i = k + 1;
+    else if (pos > requested_pos)
+      j = k;
+    else
+      return pCluster;
+  }
+
+  assert(i == j);
+  // assert(Cluster::HasBlockEntries(this, tp.m_pos));
+
+  Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
+  if (pCluster == NULL)
+    return NULL;
+
+  const ptrdiff_t idx = i - m_clusters;
+
+  if (!PreloadCluster(pCluster, idx)) {
+    delete pCluster;
+    return NULL;
+  }
+  assert(m_clusters);
+  assert(m_clusterPreloadCount > 0);
+  assert(m_clusters[idx] == pCluster);
+
+  return pCluster;
+}
+
+CuePoint::CuePoint(long idx, long long pos)
+    : m_element_start(0),
+      m_element_size(0),
+      m_index(idx),
+      m_timecode(-1 * pos),
+      m_track_positions(NULL),
+      m_track_positions_count(0) {
+  assert(pos > 0);
+}
+
+CuePoint::~CuePoint() { delete[] m_track_positions; }
+
+bool CuePoint::Load(IMkvReader* pReader) {
+  // odbgstream os;
+  // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
+
+  if (m_timecode >= 0)  // already loaded
+    return true;
+
+  assert(m_track_positions == NULL);
+  assert(m_track_positions_count == 0);
+
+  long long pos_ = -m_timecode;
+  const long long element_start = pos_;
+
+  long long stop;
+
+  {
+    long len;
+
+    const long long id = ReadID(pReader, pos_, len);
+    if (id != libwebm::kMkvCuePoint)
+      return false;
+
+    pos_ += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos_, len);
+    assert(size >= 0);
+
+    pos_ += len;  // consume Size field
+    // pos_ now points to start of payload
+
+    stop = pos_ + size;
+  }
+
+  const long long element_size = stop - element_start;
+
+  long long pos = pos_;
+
+  // First count number of track positions
+
+  while (pos < stop) {
+    long len;
+
+    const long long id = ReadID(pReader, pos, len);
+    if ((id < 0) || (pos + len > stop)) {
+      return false;
+    }
+
+    pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos, len);
+    if ((size < 0) || (pos + len > stop)) {
+      return false;
+    }
+
+    pos += len;  // consume Size field
+    if ((pos + size) > stop) {
+      return false;
+    }
+
+    if (id == libwebm::kMkvCueTime)
+      m_timecode = UnserializeUInt(pReader, pos, size);
+
+    else if (id == libwebm::kMkvCueTrackPositions)
+      ++m_track_positions_count;
+
+    pos += size;  // consume payload
+  }
+
+  if (m_timecode < 0 || m_track_positions_count <= 0) {
+    return false;
+  }
+
+  // os << "CuePoint::Load(cont'd): idpos=" << idpos
+  //   << " timecode=" << m_timecode
+  //   << endl;
+
+  m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
+  if (m_track_positions == NULL)
+    return false;
+
+  // Now parse track positions
+
+  TrackPosition* p = m_track_positions;
+  pos = pos_;
+
+  while (pos < stop) {
+    long len;
+
+    const long long id = ReadID(pReader, pos, len);
+    if (id < 0 || (pos + len) > stop)
+      return false;
+
+    pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos, len);
+    assert(size >= 0);
+    assert((pos + len) <= stop);
+
+    pos += len;  // consume Size field
+    assert((pos + size) <= stop);
+
+    if (id == libwebm::kMkvCueTrackPositions) {
+      TrackPosition& tp = *p++;
+      if (!tp.Parse(pReader, pos, size)) {
+        return false;
+      }
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return false;
+  }
+
+  assert(size_t(p - m_track_positions) == m_track_positions_count);
+
+  m_element_start = element_start;
+  m_element_size = element_size;
+
+  return true;
+}
+
+bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
+                                    long long size_) {
+  const long long stop = start_ + size_;
+  long long pos = start_;
+
+  m_track = -1;
+  m_pos = -1;
+  m_block = 1;  // default
+
+  while (pos < stop) {
+    long len;
+
+    const long long id = ReadID(pReader, pos, len);
+    if ((id < 0) || ((pos + len) > stop)) {
+      return false;
+    }
+
+    pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos, len);
+    if ((size < 0) || ((pos + len) > stop)) {
+      return false;
+    }
+
+    pos += len;  // consume Size field
+    if ((pos + size) > stop) {
+      return false;
+    }
+
+    if (id == libwebm::kMkvCueTrack)
+      m_track = UnserializeUInt(pReader, pos, size);
+    else if (id == libwebm::kMkvCueClusterPosition)
+      m_pos = UnserializeUInt(pReader, pos, size);
+    else if (id == libwebm::kMkvCueBlockNumber)
+      m_block = UnserializeUInt(pReader, pos, size);
+
+    pos += size;  // consume payload
+  }
+
+  if ((m_pos < 0) || (m_track <= 0)) {
+    return false;
+  }
+
+  return true;
+}
+
+const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
+  assert(pTrack);
+
+  const long long n = pTrack->GetNumber();
+
+  const TrackPosition* i = m_track_positions;
+  const TrackPosition* const j = i + m_track_positions_count;
+
+  while (i != j) {
+    const TrackPosition& p = *i++;
+
+    if (p.m_track == n)
+      return &p;
+  }
+
+  return NULL;  // no matching track number found
+}
+
+long long CuePoint::GetTimeCode() const { return m_timecode; }
+
+long long CuePoint::GetTime(const Segment* pSegment) const {
+  assert(pSegment);
+  assert(m_timecode >= 0);
+
+  const SegmentInfo* const pInfo = pSegment->GetInfo();
+  assert(pInfo);
+
+  const long long scale = pInfo->GetTimeCodeScale();
+  assert(scale >= 1);
+
+  const long long time = scale * m_timecode;
+
+  return time;
+}
+
+bool Segment::DoneParsing() const {
+  if (m_size < 0) {
+    long long total, avail;
+
+    const int status = m_pReader->Length(&total, &avail);
+
+    if (status < 0)  // error
+      return true;  // must assume done
+
+    if (total < 0)
+      return false;  // assume live stream
+
+    return (m_pos >= total);
+  }
+
+  const long long stop = m_start + m_size;
+
+  return (m_pos >= stop);
+}
+
+const Cluster* Segment::GetFirst() const {
+  if ((m_clusters == NULL) || (m_clusterCount <= 0))
+    return &m_eos;
+
+  Cluster* const pCluster = m_clusters[0];
+  assert(pCluster);
+
+  return pCluster;
+}
+
+const Cluster* Segment::GetLast() const {
+  if ((m_clusters == NULL) || (m_clusterCount <= 0))
+    return &m_eos;
+
+  const long idx = m_clusterCount - 1;
+
+  Cluster* const pCluster = m_clusters[idx];
+  assert(pCluster);
+
+  return pCluster;
+}
+
+unsigned long Segment::GetCount() const { return m_clusterCount; }
+
+const Cluster* Segment::GetNext(const Cluster* pCurr) {
+  assert(pCurr);
+  assert(pCurr != &m_eos);
+  assert(m_clusters);
+
+  long idx = pCurr->m_index;
+
+  if (idx >= 0) {
+    assert(m_clusterCount > 0);
+    assert(idx < m_clusterCount);
+    assert(pCurr == m_clusters[idx]);
+
+    ++idx;
+
+    if (idx >= m_clusterCount)
+      return &m_eos;  // caller will LoadCluster as desired
+
+    Cluster* const pNext = m_clusters[idx];
+    assert(pNext);
+    assert(pNext->m_index >= 0);
+    assert(pNext->m_index == idx);
+
+    return pNext;
+  }
+
+  assert(m_clusterPreloadCount > 0);
+
+  long long pos = pCurr->m_element_start;
+
+  assert(m_size >= 0);  // TODO
+  const long long stop = m_start + m_size;  // end of segment
+
+  {
+    long len;
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);
+    assert((pos + len) <= stop);  // TODO
+    if (result != 0)
+      return NULL;
+
+    const long long id = ReadID(m_pReader, pos, len);
+    if (id != libwebm::kMkvCluster)
+      return NULL;
+
+    pos += len;  // consume ID
+
+    // Read Size
+    result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);  // TODO
+    assert((pos + len) <= stop);  // TODO
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+    assert(size > 0);  // TODO
+    // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
+
+    pos += len;  // consume length of size of element
+    assert((pos + size) <= stop);  // TODO
+
+    // Pos now points to start of payload
+
+    pos += size;  // consume payload
+  }
+
+  long long off_next = 0;
+
+  while (pos < stop) {
+    long len;
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);
+    assert((pos + len) <= stop);  // TODO
+    if (result != 0)
+      return NULL;
+
+    const long long idpos = pos;  // pos of next (potential) cluster
+
+    const long long id = ReadID(m_pReader, idpos, len);
+    if (id < 0)
+      return NULL;
+
+    pos += len;  // consume ID
+
+    // Read Size
+    result = GetUIntLength(m_pReader, pos, len);
+    assert(result == 0);  // TODO
+    assert((pos + len) <= stop);  // TODO
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+    assert(size >= 0);  // TODO
+
+    pos += len;  // consume length of size of element
+    assert((pos + size) <= stop);  // TODO
+
+    // Pos now points to start of payload
+
+    if (size == 0)  // weird
+      continue;
+
+    if (id == libwebm::kMkvCluster) {
+      const long long off_next_ = idpos - m_start;
+
+      long long pos_;
+      long len_;
+
+      const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
+
+      assert(status >= 0);
+
+      if (status > 0) {
+        off_next = off_next_;
+        break;
+      }
+    }
+
+    pos += size;  // consume payload
+  }
+
+  if (off_next <= 0)
+    return 0;
+
+  Cluster** const ii = m_clusters + m_clusterCount;
+  Cluster** i = ii;
+
+  Cluster** const jj = ii + m_clusterPreloadCount;
+  Cluster** j = jj;
+
+  while (i < j) {
+    // INVARIANT:
+    //[0, i) < pos_next
+    //[i, j) ?
+    //[j, jj)  > pos_next
+
+    Cluster** const k = i + (j - i) / 2;
+    assert(k < jj);
+
+    Cluster* const pNext = *k;
+    assert(pNext);
+    assert(pNext->m_index < 0);
+
+    // const long long pos_ = pNext->m_pos;
+    // assert(pos_);
+    // pos = pos_ * ((pos_ < 0) ? -1 : 1);
+
+    pos = pNext->GetPosition();
+
+    if (pos < off_next)
+      i = k + 1;
+    else if (pos > off_next)
+      j = k;
+    else
+      return pNext;
+  }
+
+  assert(i == j);
+
+  Cluster* const pNext = Cluster::Create(this, -1, off_next);
+  if (pNext == NULL)
+    return NULL;
+
+  const ptrdiff_t idx_next = i - m_clusters;  // insertion position
+
+  if (!PreloadCluster(pNext, idx_next)) {
+    delete pNext;
+    return NULL;
+  }
+  assert(m_clusters);
+  assert(idx_next < m_clusterSize);
+  assert(m_clusters[idx_next] == pNext);
+
+  return pNext;
+}
+
+long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
+                        long long& pos, long& len) {
+  assert(pCurr);
+  assert(!pCurr->EOS());
+  assert(m_clusters);
+
+  pResult = 0;
+
+  if (pCurr->m_index >= 0) {  // loaded (not merely preloaded)
+    assert(m_clusters[pCurr->m_index] == pCurr);
+
+    const long next_idx = pCurr->m_index + 1;
+
+    if (next_idx < m_clusterCount) {
+      pResult = m_clusters[next_idx];
+      return 0;  // success
+    }
+
+    // curr cluster is last among loaded
+
+    const long result = LoadCluster(pos, len);
+
+    if (result < 0)  // error or underflow
+      return result;
+
+    if (result > 0)  // no more clusters
+    {
+      // pResult = &m_eos;
+      return 1;
+    }
+
+    pResult = GetLast();
+    return 0;  // success
+  }
+
+  assert(m_pos > 0);
+
+  long long total, avail;
+
+  long status = m_pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
+
+  // interrogate curr cluster
+
+  pos = pCurr->m_element_start;
+
+  if (pCurr->m_element_size >= 0)
+    pos += pCurr->m_element_size;
+  else {
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadUInt(m_pReader, pos, len);
+
+    if (id != libwebm::kMkvCluster)
+      return -1;
+
+    pos += len;  // consume ID
+
+    // Read Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    pos += len;  // consume size field
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size == unknown_size)  // TODO: should never happen
+      return E_FILE_FORMAT_INVALID;  // TODO: resolve this
+
+    // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
+
+    if ((segment_stop >= 0) && ((pos + size) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    // Pos now points to start of payload
+
+    pos += size;  // consume payload (that is, the current cluster)
+    if (segment_stop >= 0 && pos > segment_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    // By consuming the payload, we are assuming that the curr
+    // cluster isn't interesting.  That is, we don't bother checking
+    // whether the payload of the curr cluster is less than what
+    // happens to be available (obtained via IMkvReader::Length).
+    // Presumably the caller has already dispensed with the current
+    // cluster, and really does want the next cluster.
+  }
+
+  // pos now points to just beyond the last fully-loaded cluster
+
+  for (;;) {
+    const long status = DoParseNext(pResult, pos, len);
+
+    if (status <= 1)
+      return status;
+  }
+}
+
+long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
+  long long total, avail;
+
+  long status = m_pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
+
+  // Parse next cluster.  This is strictly a parsing activity.
+  // Creation of a new cluster object happens later, after the
+  // parsing is done.
+
+  long long off_next = 0;
+  long long cluster_size = -1;
+
+  for (;;) {
+    if ((total >= 0) && (pos >= total))
+      return 1;  // EOF
+
+    if ((segment_stop >= 0) && (pos >= segment_stop))
+      return 1;  // EOF
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long idpos = pos;  // absolute
+    const long long idoff = pos - m_start;  // relative
+
+    const long long id = ReadID(m_pReader, idpos, len);  // absolute
+
+    if (id < 0)  // error
+      return static_cast<long>(id);
+
+    if (id == 0)  // weird
+      return -1;  // generic error
+
+    pos += len;  // consume ID
+
+    // Read Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(m_pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(m_pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    pos += len;  // consume length of size of element
+
+    // Pos now points to start of payload
+
+    if (size == 0)  // weird
+      continue;
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if ((segment_stop >= 0) && (size != unknown_size) &&
+        ((pos + size) > segment_stop)) {
+      return E_FILE_FORMAT_INVALID;
+    }
+
+    if (id == libwebm::kMkvCues) {
+      if (size == unknown_size)
+        return E_FILE_FORMAT_INVALID;
+
+      const long long element_stop = pos + size;
+
+      if ((segment_stop >= 0) && (element_stop > segment_stop))
+        return E_FILE_FORMAT_INVALID;
+
+      const long long element_start = idpos;
+      const long long element_size = element_stop - element_start;
+
+      if (m_pCues == NULL) {
+        m_pCues = new (std::nothrow)
+            Cues(this, pos, size, element_start, element_size);
+        if (m_pCues == NULL)
+          return false;
+      }
+
+      pos += size;  // consume payload
+      if (segment_stop >= 0 && pos > segment_stop)
+        return E_FILE_FORMAT_INVALID;
+
+      continue;
+    }
+
+    if (id != libwebm::kMkvCluster) {  // not a Cluster ID
+      if (size == unknown_size)
+        return E_FILE_FORMAT_INVALID;
+
+      pos += size;  // consume payload
+      if (segment_stop >= 0 && pos > segment_stop)
+        return E_FILE_FORMAT_INVALID;
+
+      continue;
+    }
+
+    // We have a cluster.
+    off_next = idoff;
+
+    if (size != unknown_size)
+      cluster_size = size;
+
+    break;
+  }
+
+  assert(off_next > 0);  // have cluster
+
+  // We have parsed the next cluster.
+  // We have not created a cluster object yet.  What we need
+  // to do now is determine whether it has already be preloaded
+  //(in which case, an object for this cluster has already been
+  // created), and if not, create a new cluster object.
+
+  Cluster** const ii = m_clusters + m_clusterCount;
+  Cluster** i = ii;
+
+  Cluster** const jj = ii + m_clusterPreloadCount;
+  Cluster** j = jj;
+
+  while (i < j) {
+    // INVARIANT:
+    //[0, i) < pos_next
+    //[i, j) ?
+    //[j, jj)  > pos_next
+
+    Cluster** const k = i + (j - i) / 2;
+    assert(k < jj);
+
+    const Cluster* const pNext = *k;
+    assert(pNext);
+    assert(pNext->m_index < 0);
+
+    pos = pNext->GetPosition();
+    assert(pos >= 0);
+
+    if (pos < off_next)
+      i = k + 1;
+    else if (pos > off_next)
+      j = k;
+    else {
+      pResult = pNext;
+      return 0;  // success
+    }
+  }
+
+  assert(i == j);
+
+  long long pos_;
+  long len_;
+
+  status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
+
+  if (status < 0) {  // error or underflow
+    pos = pos_;
+    len = len_;
+
+    return status;
+  }
+
+  if (status > 0) {  // means "found at least one block entry"
+    Cluster* const pNext = Cluster::Create(this,
+                                           -1,  // preloaded
+                                           off_next);
+    if (pNext == NULL)
+      return -1;
+
+    const ptrdiff_t idx_next = i - m_clusters;  // insertion position
+
+    if (!PreloadCluster(pNext, idx_next)) {
+      delete pNext;
+      return -1;
+    }
+    assert(m_clusters);
+    assert(idx_next < m_clusterSize);
+    assert(m_clusters[idx_next] == pNext);
+
+    pResult = pNext;
+    return 0;  // success
+  }
+
+  // status == 0 means "no block entries found"
+
+  if (cluster_size < 0) {  // unknown size
+    const long long payload_pos = pos;  // absolute pos of cluster payload
+
+    for (;;) {  // determine cluster size
+      if ((total >= 0) && (pos >= total))
+        break;
+
+      if ((segment_stop >= 0) && (pos >= segment_stop))
+        break;  // no more clusters
+
+      // Read ID
+
+      if ((pos + 1) > avail) {
+        len = 1;
+        return E_BUFFER_NOT_FULL;
+      }
+
+      long long result = GetUIntLength(m_pReader, pos, len);
+
+      if (result < 0)  // error
+        return static_cast<long>(result);
+
+      if (result > 0)  // weird
+        return E_BUFFER_NOT_FULL;
+
+      if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+        return E_FILE_FORMAT_INVALID;
+
+      if ((pos + len) > avail)
+        return E_BUFFER_NOT_FULL;
+
+      const long long idpos = pos;
+      const long long id = ReadID(m_pReader, idpos, len);
+
+      if (id < 0)  // error (or underflow)
+        return static_cast<long>(id);
+
+      // This is the distinguished set of ID's we use to determine
+      // that we have exhausted the sub-element's inside the cluster
+      // whose ID we parsed earlier.
+
+      if (id == libwebm::kMkvCluster || id == libwebm::kMkvCues)
+        break;
+
+      pos += len;  // consume ID (of sub-element)
+
+      // Read Size
+
+      if ((pos + 1) > avail) {
+        len = 1;
+        return E_BUFFER_NOT_FULL;
+      }
+
+      result = GetUIntLength(m_pReader, pos, len);
+
+      if (result < 0)  // error
+        return static_cast<long>(result);
+
+      if (result > 0)  // weird
+        return E_BUFFER_NOT_FULL;
+
+      if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+        return E_FILE_FORMAT_INVALID;
+
+      if ((pos + len) > avail)
+        return E_BUFFER_NOT_FULL;
+
+      const long long size = ReadUInt(m_pReader, pos, len);
+
+      if (size < 0)  // error
+        return static_cast<long>(size);
+
+      pos += len;  // consume size field of element
+
+      // pos now points to start of sub-element's payload
+
+      if (size == 0)  // weird
+        continue;
+
+      const long long unknown_size = (1LL << (7 * len)) - 1;
+
+      if (size == unknown_size)
+        return E_FILE_FORMAT_INVALID;  // not allowed for sub-elements
+
+      if ((segment_stop >= 0) && ((pos + size) > segment_stop))  // weird
+        return E_FILE_FORMAT_INVALID;
+
+      pos += size;  // consume payload of sub-element
+      if (segment_stop >= 0 && pos > segment_stop)
+        return E_FILE_FORMAT_INVALID;
+    }  // determine cluster size
+
+    cluster_size = pos - payload_pos;
+    assert(cluster_size >= 0);  // TODO: handle cluster_size = 0
+
+    pos = payload_pos;  // reset and re-parse original cluster
+  }
+
+  pos += cluster_size;  // consume payload
+  if (segment_stop >= 0 && pos > segment_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 2;  // try to find a cluster that follows next
+}
+
+const Cluster* Segment::FindCluster(long long time_ns) const {
+  if ((m_clusters == NULL) || (m_clusterCount <= 0))
+    return &m_eos;
+
+  {
+    Cluster* const pCluster = m_clusters[0];
+    assert(pCluster);
+    assert(pCluster->m_index == 0);
+
+    if (time_ns <= pCluster->GetTime())
+      return pCluster;
+  }
+
+  // Binary search of cluster array
+
+  long i = 0;
+  long j = m_clusterCount;
+
+  while (i < j) {
+    // INVARIANT:
+    //[0, i) <= time_ns
+    //[i, j) ?
+    //[j, m_clusterCount)  > time_ns
+
+    const long k = i + (j - i) / 2;
+    assert(k < m_clusterCount);
+
+    Cluster* const pCluster = m_clusters[k];
+    assert(pCluster);
+    assert(pCluster->m_index == k);
+
+    const long long t = pCluster->GetTime();
+
+    if (t <= time_ns)
+      i = k + 1;
+    else
+      j = k;
+
+    assert(i <= j);
+  }
+
+  assert(i == j);
+  assert(i > 0);
+  assert(i <= m_clusterCount);
+
+  const long k = i - 1;
+
+  Cluster* const pCluster = m_clusters[k];
+  assert(pCluster);
+  assert(pCluster->m_index == k);
+  assert(pCluster->GetTime() <= time_ns);
+
+  return pCluster;
+}
+
+const Tracks* Segment::GetTracks() const { return m_pTracks; }
+const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
+const Cues* Segment::GetCues() const { return m_pCues; }
+const Chapters* Segment::GetChapters() const { return m_pChapters; }
+const Tags* Segment::GetTags() const { return m_pTags; }
+const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
+
+long long Segment::GetDuration() const {
+  assert(m_pInfo);
+  return m_pInfo->GetDuration();
+}
+
+Chapters::Chapters(Segment* pSegment, long long payload_start,
+                   long long payload_size, long long element_start,
+                   long long element_size)
+    : m_pSegment(pSegment),
+      m_start(payload_start),
+      m_size(payload_size),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_editions(NULL),
+      m_editions_size(0),
+      m_editions_count(0) {}
+
+Chapters::~Chapters() {
+  while (m_editions_count > 0) {
+    Edition& e = m_editions[--m_editions_count];
+    e.Clear();
+  }
+  delete[] m_editions;
+}
+
+long Chapters::Parse() {
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = m_start;  // payload start
+  const long long stop = pos + m_size;  // payload stop
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)  // weird
+      continue;
+
+    if (id == libwebm::kMkvEditionEntry) {
+      status = ParseEdition(pos, size);
+
+      if (status < 0)  // error
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+int Chapters::GetEditionCount() const { return m_editions_count; }
+
+const Chapters::Edition* Chapters::GetEdition(int idx) const {
+  if (idx < 0)
+    return NULL;
+
+  if (idx >= m_editions_count)
+    return NULL;
+
+  return m_editions + idx;
+}
+
+bool Chapters::ExpandEditionsArray() {
+  if (m_editions_size > m_editions_count)
+    return true;  // nothing else to do
+
+  const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
+
+  Edition* const editions = new (std::nothrow) Edition[size];
+
+  if (editions == NULL)
+    return false;
+
+  for (int idx = 0; idx < m_editions_count; ++idx) {
+    m_editions[idx].ShallowCopy(editions[idx]);
+  }
+
+  delete[] m_editions;
+  m_editions = editions;
+
+  m_editions_size = size;
+  return true;
+}
+
+long Chapters::ParseEdition(long long pos, long long size) {
+  if (!ExpandEditionsArray())
+    return -1;
+
+  Edition& e = m_editions[m_editions_count++];
+  e.Init();
+
+  return e.Parse(m_pSegment->m_pReader, pos, size);
+}
+
+Chapters::Edition::Edition() {}
+
+Chapters::Edition::~Edition() {}
+
+int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
+
+const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
+  if (index < 0)
+    return NULL;
+
+  if (index >= m_atoms_count)
+    return NULL;
+
+  return m_atoms + index;
+}
+
+void Chapters::Edition::Init() {
+  m_atoms = NULL;
+  m_atoms_size = 0;
+  m_atoms_count = 0;
+}
+
+void Chapters::Edition::ShallowCopy(Edition& rhs) const {
+  rhs.m_atoms = m_atoms;
+  rhs.m_atoms_size = m_atoms_size;
+  rhs.m_atoms_count = m_atoms_count;
+}
+
+void Chapters::Edition::Clear() {
+  while (m_atoms_count > 0) {
+    Atom& a = m_atoms[--m_atoms_count];
+    a.Clear();
+  }
+
+  delete[] m_atoms;
+  m_atoms = NULL;
+
+  m_atoms_size = 0;
+}
+
+long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
+                              long long size) {
+  const long long stop = pos + size;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)
+      continue;
+
+    if (id == libwebm::kMkvChapterAtom) {
+      status = ParseAtom(pReader, pos, size);
+
+      if (status < 0)  // error
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
+                                  long long size) {
+  if (!ExpandAtomsArray())
+    return -1;
+
+  Atom& a = m_atoms[m_atoms_count++];
+  a.Init();
+
+  return a.Parse(pReader, pos, size);
+}
+
+bool Chapters::Edition::ExpandAtomsArray() {
+  if (m_atoms_size > m_atoms_count)
+    return true;  // nothing else to do
+
+  const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
+
+  Atom* const atoms = new (std::nothrow) Atom[size];
+
+  if (atoms == NULL)
+    return false;
+
+  for (int idx = 0; idx < m_atoms_count; ++idx) {
+    m_atoms[idx].ShallowCopy(atoms[idx]);
+  }
+
+  delete[] m_atoms;
+  m_atoms = atoms;
+
+  m_atoms_size = size;
+  return true;
+}
+
+Chapters::Atom::Atom() {}
+
+Chapters::Atom::~Atom() {}
+
+unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
+
+const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
+
+long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
+
+long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
+
+long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
+  return GetTime(pChapters, m_start_timecode);
+}
+
+long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
+  return GetTime(pChapters, m_stop_timecode);
+}
+
+int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
+
+const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
+  if (index < 0)
+    return NULL;
+
+  if (index >= m_displays_count)
+    return NULL;
+
+  return m_displays + index;
+}
+
+void Chapters::Atom::Init() {
+  m_string_uid = NULL;
+  m_uid = 0;
+  m_start_timecode = -1;
+  m_stop_timecode = -1;
+
+  m_displays = NULL;
+  m_displays_size = 0;
+  m_displays_count = 0;
+}
+
+void Chapters::Atom::ShallowCopy(Atom& rhs) const {
+  rhs.m_string_uid = m_string_uid;
+  rhs.m_uid = m_uid;
+  rhs.m_start_timecode = m_start_timecode;
+  rhs.m_stop_timecode = m_stop_timecode;
+
+  rhs.m_displays = m_displays;
+  rhs.m_displays_size = m_displays_size;
+  rhs.m_displays_count = m_displays_count;
+}
+
+void Chapters::Atom::Clear() {
+  delete[] m_string_uid;
+  m_string_uid = NULL;
+
+  while (m_displays_count > 0) {
+    Display& d = m_displays[--m_displays_count];
+    d.Clear();
+  }
+
+  delete[] m_displays;
+  m_displays = NULL;
+
+  m_displays_size = 0;
+}
+
+long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
+  const long long stop = pos + size;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)  // 0 length payload, skip.
+      continue;
+
+    if (id == libwebm::kMkvChapterDisplay) {
+      status = ParseDisplay(pReader, pos, size);
+
+      if (status < 0)  // error
+        return status;
+    } else if (id == libwebm::kMkvChapterStringUID) {
+      status = UnserializeString(pReader, pos, size, m_string_uid);
+
+      if (status < 0)  // error
+        return status;
+    } else if (id == libwebm::kMkvChapterUID) {
+      long long val;
+      status = UnserializeInt(pReader, pos, size, val);
+
+      if (status < 0)  // error
+        return status;
+
+      m_uid = static_cast<unsigned long long>(val);
+    } 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 == libwebm::kMkvChapterTimeEnd) {
+      const long long val = UnserializeUInt(pReader, pos, size);
+
+      if (val < 0)  // error
+        return static_cast<long>(val);
+
+      m_stop_timecode = val;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+long long Chapters::Atom::GetTime(const Chapters* pChapters,
+                                  long long timecode) {
+  if (pChapters == NULL)
+    return -1;
+
+  Segment* const pSegment = pChapters->m_pSegment;
+
+  if (pSegment == NULL)  // weird
+    return -1;
+
+  const SegmentInfo* const pInfo = pSegment->GetInfo();
+
+  if (pInfo == NULL)
+    return -1;
+
+  const long long timecode_scale = pInfo->GetTimeCodeScale();
+
+  if (timecode_scale < 1)  // weird
+    return -1;
+
+  if (timecode < 0)
+    return -1;
+
+  const long long result = timecode_scale * timecode;
+
+  return result;
+}
+
+long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
+                                  long long size) {
+  if (!ExpandDisplaysArray())
+    return -1;
+
+  Display& d = m_displays[m_displays_count++];
+  d.Init();
+
+  return d.Parse(pReader, pos, size);
+}
+
+bool Chapters::Atom::ExpandDisplaysArray() {
+  if (m_displays_size > m_displays_count)
+    return true;  // nothing else to do
+
+  const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
+
+  Display* const displays = new (std::nothrow) Display[size];
+
+  if (displays == NULL)
+    return false;
+
+  for (int idx = 0; idx < m_displays_count; ++idx) {
+    m_displays[idx].ShallowCopy(displays[idx]);
+  }
+
+  delete[] m_displays;
+  m_displays = displays;
+
+  m_displays_size = size;
+  return true;
+}
+
+Chapters::Display::Display() {}
+
+Chapters::Display::~Display() {}
+
+const char* Chapters::Display::GetString() const { return m_string; }
+
+const char* Chapters::Display::GetLanguage() const { return m_language; }
+
+const char* Chapters::Display::GetCountry() const { return m_country; }
+
+void Chapters::Display::Init() {
+  m_string = NULL;
+  m_language = NULL;
+  m_country = NULL;
+}
+
+void Chapters::Display::ShallowCopy(Display& rhs) const {
+  rhs.m_string = m_string;
+  rhs.m_language = m_language;
+  rhs.m_country = m_country;
+}
+
+void Chapters::Display::Clear() {
+  delete[] m_string;
+  m_string = NULL;
+
+  delete[] m_language;
+  m_language = NULL;
+
+  delete[] m_country;
+  m_country = NULL;
+}
+
+long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
+                              long long size) {
+  const long long stop = pos + size;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)  // No payload.
+      continue;
+
+    if (id == libwebm::kMkvChapString) {
+      status = UnserializeString(pReader, pos, size, m_string);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvChapLanguage) {
+      status = UnserializeString(pReader, pos, size, m_language);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvChapCountry) {
+      status = UnserializeString(pReader, pos, size, m_country);
+
+      if (status)
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
+           long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_start(payload_start),
+      m_size(payload_size),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_tags(NULL),
+      m_tags_size(0),
+      m_tags_count(0) {}
+
+Tags::~Tags() {
+  while (m_tags_count > 0) {
+    Tag& t = m_tags[--m_tags_count];
+    t.Clear();
+  }
+  delete[] m_tags;
+}
+
+long Tags::Parse() {
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = m_start;  // payload start
+  const long long stop = pos + m_size;  // payload stop
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)
+      return status;
+
+    if (size == 0)  // 0 length tag, read another
+      continue;
+
+    if (id == libwebm::kMkvTag) {
+      status = ParseTag(pos, size);
+
+      if (status < 0)
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+int Tags::GetTagCount() const { return m_tags_count; }
+
+const Tags::Tag* Tags::GetTag(int idx) const {
+  if (idx < 0)
+    return NULL;
+
+  if (idx >= m_tags_count)
+    return NULL;
+
+  return m_tags + idx;
+}
+
+bool Tags::ExpandTagsArray() {
+  if (m_tags_size > m_tags_count)
+    return true;  // nothing else to do
+
+  const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
+
+  Tag* const tags = new (std::nothrow) Tag[size];
+
+  if (tags == NULL)
+    return false;
+
+  for (int idx = 0; idx < m_tags_count; ++idx) {
+    m_tags[idx].ShallowCopy(tags[idx]);
+  }
+
+  delete[] m_tags;
+  m_tags = tags;
+
+  m_tags_size = size;
+  return true;
+}
+
+long Tags::ParseTag(long long pos, long long size) {
+  if (!ExpandTagsArray())
+    return -1;
+
+  Tag& t = m_tags[m_tags_count++];
+  t.Init();
+
+  return t.Parse(m_pSegment->m_pReader, pos, size);
+}
+
+Tags::Tag::Tag() {}
+
+Tags::Tag::~Tag() {}
+
+int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
+
+const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
+  if (index < 0)
+    return NULL;
+
+  if (index >= m_simple_tags_count)
+    return NULL;
+
+  return m_simple_tags + index;
+}
+
+void Tags::Tag::Init() {
+  m_simple_tags = NULL;
+  m_simple_tags_size = 0;
+  m_simple_tags_count = 0;
+}
+
+void Tags::Tag::ShallowCopy(Tag& rhs) const {
+  rhs.m_simple_tags = m_simple_tags;
+  rhs.m_simple_tags_size = m_simple_tags_size;
+  rhs.m_simple_tags_count = m_simple_tags_count;
+}
+
+void Tags::Tag::Clear() {
+  while (m_simple_tags_count > 0) {
+    SimpleTag& d = m_simple_tags[--m_simple_tags_count];
+    d.Clear();
+  }
+
+  delete[] m_simple_tags;
+  m_simple_tags = NULL;
+
+  m_simple_tags_size = 0;
+}
+
+long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
+  const long long stop = pos + size;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)
+      return status;
+
+    if (size == 0)  // 0 length tag, read another
+      continue;
+
+    if (id == libwebm::kMkvSimpleTag) {
+      status = ParseSimpleTag(pReader, pos, size);
+
+      if (status < 0)
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
+                               long long size) {
+  if (!ExpandSimpleTagsArray())
+    return -1;
+
+  SimpleTag& st = m_simple_tags[m_simple_tags_count++];
+  st.Init();
+
+  return st.Parse(pReader, pos, size);
+}
+
+bool Tags::Tag::ExpandSimpleTagsArray() {
+  if (m_simple_tags_size > m_simple_tags_count)
+    return true;  // nothing else to do
+
+  const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
+
+  SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
+
+  if (displays == NULL)
+    return false;
+
+  for (int idx = 0; idx < m_simple_tags_count; ++idx) {
+    m_simple_tags[idx].ShallowCopy(displays[idx]);
+  }
+
+  delete[] m_simple_tags;
+  m_simple_tags = displays;
+
+  m_simple_tags_size = size;
+  return true;
+}
+
+Tags::SimpleTag::SimpleTag() {}
+
+Tags::SimpleTag::~SimpleTag() {}
+
+const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
+
+const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
+
+void Tags::SimpleTag::Init() {
+  m_tag_name = NULL;
+  m_tag_string = NULL;
+}
+
+void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
+  rhs.m_tag_name = m_tag_name;
+  rhs.m_tag_string = m_tag_string;
+}
+
+void Tags::SimpleTag::Clear() {
+  delete[] m_tag_name;
+  m_tag_name = NULL;
+
+  delete[] m_tag_string;
+  m_tag_string = NULL;
+}
+
+long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
+                            long long size) {
+  const long long stop = pos + size;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)  // weird
+      continue;
+
+    if (id == libwebm::kMkvTagName) {
+      status = UnserializeString(pReader, pos, size, m_tag_name);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvTagString) {
+      status = UnserializeString(pReader, pos, size, m_tag_string);
+
+      if (status)
+        return status;
+    }
+
+    pos += size;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
+                         long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_start(start),
+      m_size(size_),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_pMuxingAppAsUTF8(NULL),
+      m_pWritingAppAsUTF8(NULL),
+      m_pTitleAsUTF8(NULL) {}
+
+SegmentInfo::~SegmentInfo() {
+  delete[] m_pMuxingAppAsUTF8;
+  m_pMuxingAppAsUTF8 = NULL;
+
+  delete[] m_pWritingAppAsUTF8;
+  m_pWritingAppAsUTF8 = NULL;
+
+  delete[] m_pTitleAsUTF8;
+  m_pTitleAsUTF8 = NULL;
+}
+
+long SegmentInfo::Parse() {
+  assert(m_pMuxingAppAsUTF8 == NULL);
+  assert(m_pWritingAppAsUTF8 == NULL);
+  assert(m_pTitleAsUTF8 == NULL);
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = m_start;
+  const long long stop = m_start + m_size;
+
+  m_timecodeScale = 1000000;
+  m_duration = -1;
+
+  while (pos < stop) {
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvTimecodeScale) {
+      m_timecodeScale = UnserializeUInt(pReader, pos, size);
+
+      if (m_timecodeScale <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDuration) {
+      const long status = UnserializeFloat(pReader, pos, size, m_duration);
+
+      if (status < 0)
+        return status;
+
+      if (m_duration < 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvMuxingApp) {
+      const long status =
+          UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvWritingApp) {
+      const long status =
+          UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvTitle) {
+      const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
+
+      if (status)
+        return status;
+    }
+
+    pos += size;
+
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  const double rollover_check = m_duration * m_timecodeScale;
+  if (rollover_check > LLONG_MAX)
+    return E_FILE_FORMAT_INVALID;
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
+
+long long SegmentInfo::GetDuration() const {
+  if (m_duration < 0)
+    return -1;
+
+  assert(m_timecodeScale >= 1);
+
+  const double dd = double(m_duration) * double(m_timecodeScale);
+  const long long d = static_cast<long long>(dd);
+
+  return d;
+}
+
+const char* SegmentInfo::GetMuxingAppAsUTF8() const {
+  return m_pMuxingAppAsUTF8;
+}
+
+const char* SegmentInfo::GetWritingAppAsUTF8() const {
+  return m_pWritingAppAsUTF8;
+}
+
+const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
+
+///////////////////////////////////////////////////////////////
+// ContentEncoding element
+ContentEncoding::ContentCompression::ContentCompression()
+    : algo(0), settings(NULL), settings_len(0) {}
+
+ContentEncoding::ContentCompression::~ContentCompression() {
+  delete[] settings;
+}
+
+ContentEncoding::ContentEncryption::ContentEncryption()
+    : algo(0),
+      key_id(NULL),
+      key_id_len(0),
+      signature(NULL),
+      signature_len(0),
+      sig_key_id(NULL),
+      sig_key_id_len(0),
+      sig_algo(0),
+      sig_hash_algo(0) {}
+
+ContentEncoding::ContentEncryption::~ContentEncryption() {
+  delete[] key_id;
+  delete[] signature;
+  delete[] sig_key_id;
+}
+
+ContentEncoding::ContentEncoding()
+    : compression_entries_(NULL),
+      compression_entries_end_(NULL),
+      encryption_entries_(NULL),
+      encryption_entries_end_(NULL),
+      encoding_order_(0),
+      encoding_scope_(1),
+      encoding_type_(0) {}
+
+ContentEncoding::~ContentEncoding() {
+  ContentCompression** comp_i = compression_entries_;
+  ContentCompression** const comp_j = compression_entries_end_;
+
+  while (comp_i != comp_j) {
+    ContentCompression* const comp = *comp_i++;
+    delete comp;
+  }
+
+  delete[] compression_entries_;
+
+  ContentEncryption** enc_i = encryption_entries_;
+  ContentEncryption** const enc_j = encryption_entries_end_;
+
+  while (enc_i != enc_j) {
+    ContentEncryption* const enc = *enc_i++;
+    delete enc;
+  }
+
+  delete[] encryption_entries_;
+}
+
+const ContentEncoding::ContentCompression*
+    ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
+  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
+  assert(count >= 0);
+
+  if (idx >= static_cast<unsigned long>(count))
+    return NULL;
+
+  return compression_entries_[idx];
+}
+
+unsigned long ContentEncoding::GetCompressionCount() const {
+  const ptrdiff_t count = compression_entries_end_ - compression_entries_;
+  assert(count >= 0);
+
+  return static_cast<unsigned long>(count);
+}
+
+const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
+    unsigned long idx) const {
+  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
+  assert(count >= 0);
+
+  if (idx >= static_cast<unsigned long>(count))
+    return NULL;
+
+  return encryption_entries_[idx];
+}
+
+unsigned long ContentEncoding::GetEncryptionCount() const {
+  const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
+  assert(count >= 0);
+
+  return static_cast<unsigned long>(count);
+}
+
+long ContentEncoding::ParseContentEncAESSettingsEntry(
+    long long start, long long size, IMkvReader* pReader,
+    ContentEncAESSettings* aes) {
+  assert(pReader);
+  assert(aes);
+
+  long long pos = start;
+  const long long stop = start + size;
+
+  while (pos < stop) {
+    long long id, size;
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvAESSettingsCipherMode) {
+      aes->cipher_mode = UnserializeUInt(pReader, pos, size);
+      if (aes->cipher_mode != 1)
+        return E_FILE_FORMAT_INVALID;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  return 0;
+}
+
+long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
+                                                IMkvReader* pReader) {
+  assert(pReader);
+
+  long long pos = start;
+  const long long stop = start + size;
+
+  // Count ContentCompression and ContentEncryption elements.
+  int compression_count = 0;
+  int encryption_count = 0;
+
+  while (pos < stop) {
+    long long id, size;
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvContentCompression)
+      ++compression_count;
+
+    if (id == libwebm::kMkvContentEncryption)
+      ++encryption_count;
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (compression_count <= 0 && encryption_count <= 0)
+    return -1;
+
+  if (compression_count > 0) {
+    compression_entries_ =
+        new (std::nothrow) ContentCompression*[compression_count];
+    if (!compression_entries_)
+      return -1;
+    compression_entries_end_ = compression_entries_;
+  }
+
+  if (encryption_count > 0) {
+    encryption_entries_ =
+        new (std::nothrow) ContentEncryption*[encryption_count];
+    if (!encryption_entries_) {
+      delete[] compression_entries_;
+      return -1;
+    }
+    encryption_entries_end_ = encryption_entries_;
+  }
+
+  pos = start;
+  while (pos < stop) {
+    long long id, size;
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvContentEncodingOrder) {
+      encoding_order_ = UnserializeUInt(pReader, pos, size);
+    } else if (id == libwebm::kMkvContentEncodingScope) {
+      encoding_scope_ = UnserializeUInt(pReader, pos, size);
+      if (encoding_scope_ < 1)
+        return -1;
+    } else if (id == libwebm::kMkvContentEncodingType) {
+      encoding_type_ = UnserializeUInt(pReader, pos, size);
+    } else if (id == libwebm::kMkvContentCompression) {
+      ContentCompression* const compression =
+          new (std::nothrow) ContentCompression();
+      if (!compression)
+        return -1;
+
+      status = ParseCompressionEntry(pos, size, pReader, compression);
+      if (status) {
+        delete compression;
+        return status;
+      }
+      *compression_entries_end_++ = compression;
+    } else if (id == libwebm::kMkvContentEncryption) {
+      ContentEncryption* const encryption =
+          new (std::nothrow) ContentEncryption();
+      if (!encryption)
+        return -1;
+
+      status = ParseEncryptionEntry(pos, size, pReader, encryption);
+      if (status) {
+        delete encryption;
+        return status;
+      }
+      *encryption_entries_end_++ = encryption;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  return 0;
+}
+
+long ContentEncoding::ParseCompressionEntry(long long start, long long size,
+                                            IMkvReader* pReader,
+                                            ContentCompression* compression) {
+  assert(pReader);
+  assert(compression);
+
+  long long pos = start;
+  const long long stop = start + size;
+
+  bool valid = false;
+
+  while (pos < stop) {
+    long long id, size;
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    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 == libwebm::kMkvContentCompSettings) {
+      if (size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      const size_t buflen = static_cast<size_t>(size);
+      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
+      if (buf == NULL)
+        return -1;
+
+      const int read_status =
+          pReader->Read(pos, static_cast<long>(buflen), buf);
+      if (read_status) {
+        delete[] buf;
+        return status;
+      }
+
+      compression->settings = buf;
+      compression->settings_len = buflen;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  // ContentCompAlgo is mandatory
+  if (!valid)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
+                                           IMkvReader* pReader,
+                                           ContentEncryption* encryption) {
+  assert(pReader);
+  assert(encryption);
+
+  long long pos = start;
+  const long long stop = start + size;
+
+  while (pos < stop) {
+    long long id, size;
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvContentEncAlgo) {
+      encryption->algo = UnserializeUInt(pReader, pos, size);
+      if (encryption->algo != 5)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvContentEncKeyID) {
+      delete[] encryption->key_id;
+      encryption->key_id = NULL;
+      encryption->key_id_len = 0;
+
+      if (size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      const size_t buflen = static_cast<size_t>(size);
+      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
+      if (buf == NULL)
+        return -1;
+
+      const int read_status =
+          pReader->Read(pos, static_cast<long>(buflen), buf);
+      if (read_status) {
+        delete[] buf;
+        return status;
+      }
+
+      encryption->key_id = buf;
+      encryption->key_id_len = buflen;
+    } else if (id == libwebm::kMkvContentSignature) {
+      delete[] encryption->signature;
+      encryption->signature = NULL;
+      encryption->signature_len = 0;
+
+      if (size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      const size_t buflen = static_cast<size_t>(size);
+      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
+      if (buf == NULL)
+        return -1;
+
+      const int read_status =
+          pReader->Read(pos, static_cast<long>(buflen), buf);
+      if (read_status) {
+        delete[] buf;
+        return status;
+      }
+
+      encryption->signature = buf;
+      encryption->signature_len = buflen;
+    } else if (id == libwebm::kMkvContentSigKeyID) {
+      delete[] encryption->sig_key_id;
+      encryption->sig_key_id = NULL;
+      encryption->sig_key_id_len = 0;
+
+      if (size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      const size_t buflen = static_cast<size_t>(size);
+      unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
+      if (buf == NULL)
+        return -1;
+
+      const int read_status =
+          pReader->Read(pos, static_cast<long>(buflen), buf);
+      if (read_status) {
+        delete[] buf;
+        return status;
+      }
+
+      encryption->sig_key_id = buf;
+      encryption->sig_key_id_len = buflen;
+    } else if (id == libwebm::kMkvContentSigAlgo) {
+      encryption->sig_algo = UnserializeUInt(pReader, pos, size);
+    } else if (id == libwebm::kMkvContentSigHashAlgo) {
+      encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
+    } else if (id == libwebm::kMkvContentEncAESSettings) {
+      const long status = ParseContentEncAESSettingsEntry(
+          pos, size, pReader, &encryption->aes_settings);
+      if (status)
+        return status;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  return 0;
+}
+
+Track::Track(Segment* pSegment, long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      content_encoding_entries_(NULL),
+      content_encoding_entries_end_(NULL) {}
+
+Track::~Track() {
+  Info& info = const_cast<Info&>(m_info);
+  info.Clear();
+
+  ContentEncoding** i = content_encoding_entries_;
+  ContentEncoding** const j = content_encoding_entries_end_;
+
+  while (i != j) {
+    ContentEncoding* const encoding = *i++;
+    delete encoding;
+  }
+
+  delete[] content_encoding_entries_;
+}
+
+long Track::Create(Segment* pSegment, const Info& info, long long element_start,
+                   long long element_size, Track*& pResult) {
+  if (pResult)
+    return -1;
+
+  Track* const pTrack =
+      new (std::nothrow) Track(pSegment, element_start, element_size);
+
+  if (pTrack == NULL)
+    return -1;  // generic error
+
+  const int status = info.Copy(pTrack->m_info);
+
+  if (status) {  // error
+    delete pTrack;
+    return status;
+  }
+
+  pResult = pTrack;
+  return 0;  // success
+}
+
+Track::Info::Info()
+    : uid(0),
+      defaultDuration(0),
+      codecDelay(0),
+      seekPreRoll(0),
+      nameAsUTF8(NULL),
+      language(NULL),
+      codecId(NULL),
+      codecNameAsUTF8(NULL),
+      codecPrivate(NULL),
+      codecPrivateSize(0),
+      lacing(false) {}
+
+Track::Info::~Info() { Clear(); }
+
+void Track::Info::Clear() {
+  delete[] nameAsUTF8;
+  nameAsUTF8 = NULL;
+
+  delete[] language;
+  language = NULL;
+
+  delete[] codecId;
+  codecId = NULL;
+
+  delete[] codecPrivate;
+  codecPrivate = NULL;
+  codecPrivateSize = 0;
+
+  delete[] codecNameAsUTF8;
+  codecNameAsUTF8 = NULL;
+}
+
+int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
+  if (str == static_cast<char * Info::*>(NULL))
+    return -1;
+
+  char*& dst = dst_.*str;
+
+  if (dst)  // should be NULL already
+    return -1;
+
+  const char* const src = this->*str;
+
+  if (src == NULL)
+    return 0;
+
+  const size_t len = strlen(src);
+
+  dst = SafeArrayAlloc<char>(1, len + 1);
+
+  if (dst == NULL)
+    return -1;
+
+  strcpy(dst, src);
+
+  return 0;
+}
+
+int Track::Info::Copy(Info& dst) const {
+  if (&dst == this)
+    return 0;
+
+  dst.type = type;
+  dst.number = number;
+  dst.defaultDuration = defaultDuration;
+  dst.codecDelay = codecDelay;
+  dst.seekPreRoll = seekPreRoll;
+  dst.uid = uid;
+  dst.lacing = lacing;
+  dst.settings = settings;
+
+  // We now copy the string member variables from src to dst.
+  // This involves memory allocation so in principle the operation
+  // can fail (indeed, that's why we have Info::Copy), so we must
+  // report this to the caller.  An error return from this function
+  // therefore implies that the copy was only partially successful.
+
+  if (int status = CopyStr(&Info::nameAsUTF8, dst))
+    return status;
+
+  if (int status = CopyStr(&Info::language, dst))
+    return status;
+
+  if (int status = CopyStr(&Info::codecId, dst))
+    return status;
+
+  if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
+    return status;
+
+  if (codecPrivateSize > 0) {
+    if (codecPrivate == NULL)
+      return -1;
+
+    if (dst.codecPrivate)
+      return -1;
+
+    if (dst.codecPrivateSize != 0)
+      return -1;
+
+    dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
+
+    if (dst.codecPrivate == NULL)
+      return -1;
+
+    memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
+    dst.codecPrivateSize = codecPrivateSize;
+  }
+
+  return 0;
+}
+
+const BlockEntry* Track::GetEOS() const { return &m_eos; }
+
+long Track::GetType() const { return m_info.type; }
+
+long Track::GetNumber() const { return m_info.number; }
+
+unsigned long long Track::GetUid() const { return m_info.uid; }
+
+const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
+
+const char* Track::GetLanguage() const { return m_info.language; }
+
+const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
+
+const char* Track::GetCodecId() const { return m_info.codecId; }
+
+const unsigned char* Track::GetCodecPrivate(size_t& size) const {
+  size = m_info.codecPrivateSize;
+  return m_info.codecPrivate;
+}
+
+bool Track::GetLacing() const { return m_info.lacing; }
+
+unsigned long long Track::GetDefaultDuration() const {
+  return m_info.defaultDuration;
+}
+
+unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
+
+unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
+
+long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
+  const Cluster* pCluster = m_pSegment->GetFirst();
+
+  for (int i = 0;;) {
+    if (pCluster == NULL) {
+      pBlockEntry = GetEOS();
+      return 1;
+    }
+
+    if (pCluster->EOS()) {
+      if (m_pSegment->DoneParsing()) {
+        pBlockEntry = GetEOS();
+        return 1;
+      }
+
+      pBlockEntry = 0;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long status = pCluster->GetFirst(pBlockEntry);
+
+    if (status < 0)  // error
+      return status;
+
+    if (pBlockEntry == 0) {  // empty cluster
+      pCluster = m_pSegment->GetNext(pCluster);
+      continue;
+    }
+
+    for (;;) {
+      const Block* const pBlock = pBlockEntry->GetBlock();
+      assert(pBlock);
+
+      const long long tn = pBlock->GetTrackNumber();
+
+      if ((tn == m_info.number) && VetEntry(pBlockEntry))
+        return 0;
+
+      const BlockEntry* pNextEntry;
+
+      status = pCluster->GetNext(pBlockEntry, pNextEntry);
+
+      if (status < 0)  // error
+        return status;
+
+      if (pNextEntry == 0)
+        break;
+
+      pBlockEntry = pNextEntry;
+    }
+
+    ++i;
+
+    if (i >= 100)
+      break;
+
+    pCluster = m_pSegment->GetNext(pCluster);
+  }
+
+  // NOTE: if we get here, it means that we didn't find a block with
+  // a matching track number.  We interpret that as an error (which
+  // might be too conservative).
+
+  pBlockEntry = GetEOS();  // so we can return a non-NULL value
+  return 1;
+}
+
+long Track::GetNext(const BlockEntry* pCurrEntry,
+                    const BlockEntry*& pNextEntry) const {
+  assert(pCurrEntry);
+  assert(!pCurrEntry->EOS());  //?
+
+  const Block* const pCurrBlock = pCurrEntry->GetBlock();
+  assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
+  if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
+    return -1;
+
+  const Cluster* pCluster = pCurrEntry->GetCluster();
+  assert(pCluster);
+  assert(!pCluster->EOS());
+
+  long status = pCluster->GetNext(pCurrEntry, pNextEntry);
+
+  if (status < 0)  // error
+    return status;
+
+  for (int i = 0;;) {
+    while (pNextEntry) {
+      const Block* const pNextBlock = pNextEntry->GetBlock();
+      assert(pNextBlock);
+
+      if (pNextBlock->GetTrackNumber() == m_info.number)
+        return 0;
+
+      pCurrEntry = pNextEntry;
+
+      status = pCluster->GetNext(pCurrEntry, pNextEntry);
+
+      if (status < 0)  // error
+        return status;
+    }
+
+    pCluster = m_pSegment->GetNext(pCluster);
+
+    if (pCluster == NULL) {
+      pNextEntry = GetEOS();
+      return 1;
+    }
+
+    if (pCluster->EOS()) {
+      if (m_pSegment->DoneParsing()) {
+        pNextEntry = GetEOS();
+        return 1;
+      }
+
+      // TODO: there is a potential O(n^2) problem here: we tell the
+      // caller to (pre)load another cluster, which he does, but then he
+      // calls GetNext again, which repeats the same search.  This is
+      // a pathological case, since the only way it can happen is if
+      // there exists a long sequence of clusters none of which contain a
+      // block from this track.  One way around this problem is for the
+      // caller to be smarter when he loads another cluster: don't call
+      // us back until you have a cluster that contains a block from this
+      // track. (Of course, that's not cheap either, since our caller
+      // would have to scan the each cluster as it's loaded, so that
+      // would just push back the problem.)
+
+      pNextEntry = NULL;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    status = pCluster->GetFirst(pNextEntry);
+
+    if (status < 0)  // error
+      return status;
+
+    if (pNextEntry == NULL)  // empty cluster
+      continue;
+
+    ++i;
+
+    if (i >= 100)
+      break;
+  }
+
+  // NOTE: if we get here, it means that we didn't find a block with
+  // a matching track number after lots of searching, so we give
+  // up trying.
+
+  pNextEntry = GetEOS();  // so we can return a non-NULL value
+  return 1;
+}
+
+bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
+  assert(pBlockEntry);
+  const Block* const pBlock = pBlockEntry->GetBlock();
+  assert(pBlock);
+  assert(pBlock->GetTrackNumber() == m_info.number);
+  if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
+    return false;
+
+  // This function is used during a seek to determine whether the
+  // frame is a valid seek target.  This default function simply
+  // returns true, which means all frames are valid seek targets.
+  // It gets overridden by the VideoTrack class, because only video
+  // keyframes can be used as seek target.
+
+  return true;
+}
+
+long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
+  const long status = GetFirst(pResult);
+
+  if (status < 0)  // buffer underflow, etc
+    return status;
+
+  assert(pResult);
+
+  if (pResult->EOS())
+    return 0;
+
+  const Cluster* pCluster = pResult->GetCluster();
+  assert(pCluster);
+  assert(pCluster->GetIndex() >= 0);
+
+  if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
+    return 0;
+
+  Cluster** const clusters = m_pSegment->m_clusters;
+  assert(clusters);
+
+  const long count = m_pSegment->GetCount();  // loaded only, not preloaded
+  assert(count > 0);
+
+  Cluster** const i = clusters + pCluster->GetIndex();
+  assert(i);
+  assert(*i == pCluster);
+  assert(pCluster->GetTime() <= time_ns);
+
+  Cluster** const j = clusters + count;
+
+  Cluster** lo = i;
+  Cluster** hi = j;
+
+  while (lo < hi) {
+    // INVARIANT:
+    //[i, lo) <= time_ns
+    //[lo, hi) ?
+    //[hi, j)  > time_ns
+
+    Cluster** const mid = lo + (hi - lo) / 2;
+    assert(mid < hi);
+
+    pCluster = *mid;
+    assert(pCluster);
+    assert(pCluster->GetIndex() >= 0);
+    assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
+
+    const long long t = pCluster->GetTime();
+
+    if (t <= time_ns)
+      lo = mid + 1;
+    else
+      hi = mid;
+
+    assert(lo <= hi);
+  }
+
+  assert(lo == hi);
+  assert(lo > i);
+  assert(lo <= j);
+
+  while (lo > i) {
+    pCluster = *--lo;
+    assert(pCluster);
+    assert(pCluster->GetTime() <= time_ns);
+
+    pResult = pCluster->GetEntry(this);
+
+    if ((pResult != 0) && !pResult->EOS())
+      return 0;
+
+    // landed on empty cluster (no entries)
+  }
+
+  pResult = GetEOS();  // weird
+  return 0;
+}
+
+const ContentEncoding* Track::GetContentEncodingByIndex(
+    unsigned long idx) const {
+  const ptrdiff_t count =
+      content_encoding_entries_end_ - content_encoding_entries_;
+  assert(count >= 0);
+
+  if (idx >= static_cast<unsigned long>(count))
+    return NULL;
+
+  return content_encoding_entries_[idx];
+}
+
+unsigned long Track::GetContentEncodingCount() const {
+  const ptrdiff_t count =
+      content_encoding_entries_end_ - content_encoding_entries_;
+  assert(count >= 0);
+
+  return static_cast<unsigned long>(count);
+}
+
+long Track::ParseContentEncodingsEntry(long long start, long long size) {
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+  assert(pReader);
+
+  long long pos = start;
+  const long long stop = start + size;
+
+  // Count ContentEncoding elements.
+  int count = 0;
+  while (pos < stop) {
+    long long id, size;
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    // pos now designates start of element
+    if (id == libwebm::kMkvContentEncoding)
+      ++count;
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (count <= 0)
+    return -1;
+
+  content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
+  if (!content_encoding_entries_)
+    return -1;
+
+  content_encoding_entries_end_ = content_encoding_entries_;
+
+  pos = start;
+  while (pos < stop) {
+    long long id, size;
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+    if (status < 0)  // error
+      return status;
+
+    // pos now designates start of element
+    if (id == libwebm::kMkvContentEncoding) {
+      ContentEncoding* const content_encoding =
+          new (std::nothrow) ContentEncoding();
+      if (!content_encoding)
+        return -1;
+
+      status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
+      if (status) {
+        delete content_encoding;
+        return status;
+      }
+
+      *content_encoding_entries_end_++ = content_encoding;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;
+}
+
+Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
+
+BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
+
+const Block* Track::EOSBlock::GetBlock() const { return NULL; }
+
+bool PrimaryChromaticity::Parse(IMkvReader* reader, long long read_pos,
+                                long long value_size, bool is_x,
+                                PrimaryChromaticity** chromaticity) {
+  if (!reader)
+    return false;
+
+  std::auto_ptr<PrimaryChromaticity> chromaticity_ptr;
+
+  if (!*chromaticity) {
+    chromaticity_ptr.reset(new PrimaryChromaticity());
+  } else {
+    chromaticity_ptr.reset(*chromaticity);
+  }
+
+  if (!chromaticity_ptr.get())
+    return false;
+
+  float* value = is_x ? &chromaticity_ptr->x : &chromaticity_ptr->y;
+
+  double parser_value = 0;
+  const long long value_parse_status =
+      UnserializeFloat(reader, read_pos, value_size, parser_value);
+
+  *value = static_cast<float>(parser_value);
+
+  if (value_parse_status < 0 || *value < 0.0 || *value > 1.0)
+    return false;
+
+  *chromaticity = chromaticity_ptr.release();
+  return true;
+}
+
+bool MasteringMetadata::Parse(IMkvReader* reader, long long mm_start,
+                              long long mm_size, MasteringMetadata** mm) {
+  if (!reader || *mm)
+    return false;
+
+  std::auto_ptr<MasteringMetadata> mm_ptr(new MasteringMetadata());
+  if (!mm_ptr.get())
+    return false;
+
+  const long long mm_end = mm_start + mm_size;
+  long long read_pos = mm_start;
+
+  while (read_pos < mm_end) {
+    long long child_id = 0;
+    long long child_size = 0;
+
+    const long long status =
+        ParseElementHeader(reader, read_pos, mm_end, child_id, child_size);
+    if (status < 0)
+      return false;
+
+    if (child_id == libwebm::kMkvLuminanceMax) {
+      double value = 0;
+      const long long value_parse_status =
+          UnserializeFloat(reader, read_pos, child_size, value);
+      mm_ptr->luminance_max = static_cast<float>(value);
+      if (value_parse_status < 0 || mm_ptr->luminance_max < 0.0 ||
+          mm_ptr->luminance_max > 9999.99) {
+        return false;
+      }
+    } else if (child_id == libwebm::kMkvLuminanceMin) {
+      double value = 0;
+      const long long value_parse_status =
+          UnserializeFloat(reader, read_pos, child_size, value);
+      mm_ptr->luminance_min = static_cast<float>(value);
+      if (value_parse_status < 0 || mm_ptr->luminance_min < 0.0 ||
+          mm_ptr->luminance_min > 999.9999) {
+        return false;
+      }
+    } else {
+      bool is_x = false;
+      PrimaryChromaticity** chromaticity;
+      switch (child_id) {
+        case libwebm::kMkvPrimaryRChromaticityX:
+        case libwebm::kMkvPrimaryRChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryRChromaticityX;
+          chromaticity = &mm_ptr->r;
+          break;
+        case libwebm::kMkvPrimaryGChromaticityX:
+        case libwebm::kMkvPrimaryGChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryGChromaticityX;
+          chromaticity = &mm_ptr->g;
+          break;
+        case libwebm::kMkvPrimaryBChromaticityX:
+        case libwebm::kMkvPrimaryBChromaticityY:
+          is_x = child_id == libwebm::kMkvPrimaryBChromaticityX;
+          chromaticity = &mm_ptr->b;
+          break;
+        case libwebm::kMkvWhitePointChromaticityX:
+        case libwebm::kMkvWhitePointChromaticityY:
+          is_x = child_id == libwebm::kMkvWhitePointChromaticityX;
+          chromaticity = &mm_ptr->white_point;
+          break;
+        default:
+          return false;
+      }
+      const bool value_parse_status = PrimaryChromaticity::Parse(
+          reader, read_pos, child_size, is_x, chromaticity);
+      if (!value_parse_status)
+        return false;
+    }
+
+    read_pos += child_size;
+    if (read_pos > mm_end)
+      return false;
+  }
+
+  *mm = mm_ptr.release();
+  return true;
+}
+
+bool Colour::Parse(IMkvReader* reader, long long colour_start,
+                   long long colour_size, Colour** colour) {
+  if (!reader || *colour)
+    return false;
+
+  std::auto_ptr<Colour> colour_ptr(new Colour());
+  if (!colour_ptr.get())
+    return false;
+
+  const long long colour_end = colour_start + colour_size;
+  long long read_pos = colour_start;
+
+  while (read_pos < colour_end) {
+    long long child_id = 0;
+    long long child_size = 0;
+
+    const long status =
+        ParseElementHeader(reader, read_pos, colour_end, child_id, child_size);
+    if (status < 0)
+      return false;
+
+    if (child_id == libwebm::kMkvMatrixCoefficients) {
+      colour_ptr->matrix_coefficients =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->matrix_coefficients < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvBitsPerChannel) {
+      colour_ptr->bits_per_channel =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->bits_per_channel < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSubsamplingHorz) {
+      colour_ptr->chroma_subsampling_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_subsampling_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSubsamplingVert) {
+      colour_ptr->chroma_subsampling_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_subsampling_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvCbSubsamplingHorz) {
+      colour_ptr->cb_subsampling_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->cb_subsampling_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvCbSubsamplingVert) {
+      colour_ptr->cb_subsampling_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->cb_subsampling_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSitingHorz) {
+      colour_ptr->chroma_siting_horz =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_siting_horz < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvChromaSitingVert) {
+      colour_ptr->chroma_siting_vert =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->chroma_siting_vert < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvRange) {
+      colour_ptr->range = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->range < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvTransferCharacteristics) {
+      colour_ptr->transfer_characteristics =
+          UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->transfer_characteristics < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvPrimaries) {
+      colour_ptr->primaries = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->primaries < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMaxCLL) {
+      colour_ptr->max_cll = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->max_cll < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMaxFALL) {
+      colour_ptr->max_fall = UnserializeUInt(reader, read_pos, child_size);
+      if (colour_ptr->max_fall < 0)
+        return false;
+    } else if (child_id == libwebm::kMkvMasteringMetadata) {
+      if (!MasteringMetadata::Parse(reader, read_pos, child_size,
+                                    &colour_ptr->mastering_metadata))
+        return false;
+    } else {
+      return false;
+    }
+
+    read_pos += child_size;
+    if (read_pos > colour_end)
+      return false;
+  }
+  *colour = colour_ptr.release();
+  return true;
+}
+
+VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
+                       long long element_size)
+    : Track(pSegment, element_start, element_size), m_colour(NULL) {}
+
+VideoTrack::~VideoTrack() { delete m_colour; }
+
+long VideoTrack::Parse(Segment* pSegment, const Info& info,
+                       long long element_start, long long element_size,
+                       VideoTrack*& pResult) {
+  if (pResult)
+    return -1;
+
+  if (info.type != Track::kVideo)
+    return -1;
+
+  long long width = 0;
+  long long height = 0;
+  long long display_width = 0;
+  long long display_height = 0;
+  long long display_unit = 0;
+  long long stereo_mode = 0;
+
+  double rate = 0.0;
+
+  IMkvReader* const pReader = pSegment->m_pReader;
+
+  const Settings& s = info.settings;
+  assert(s.start >= 0);
+  assert(s.size >= 0);
+
+  long long pos = s.start;
+  assert(pos >= 0);
+
+  const long long stop = pos + s.size;
+
+  Colour* colour = NULL;
+
+  while (pos < stop) {
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvPixelWidth) {
+      width = UnserializeUInt(pReader, pos, size);
+
+      if (width <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvPixelHeight) {
+      height = UnserializeUInt(pReader, pos, size);
+
+      if (height <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDisplayWidth) {
+      display_width = UnserializeUInt(pReader, pos, size);
+
+      if (display_width <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDisplayHeight) {
+      display_height = UnserializeUInt(pReader, pos, size);
+
+      if (display_height <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvDisplayUnit) {
+      display_unit = UnserializeUInt(pReader, pos, size);
+
+      if (display_unit < 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvStereoMode) {
+      stereo_mode = UnserializeUInt(pReader, pos, size);
+
+      if (stereo_mode < 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvFrameRate) {
+      const long status = UnserializeFloat(pReader, pos, size, rate);
+
+      if (status < 0)
+        return status;
+
+      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
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  VideoTrack* const pTrack =
+      new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
+
+  if (pTrack == NULL)
+    return -1;  // generic error
+
+  const int status = info.Copy(pTrack->m_info);
+
+  if (status) {  // error
+    delete pTrack;
+    return status;
+  }
+
+  pTrack->m_width = width;
+  pTrack->m_height = height;
+  pTrack->m_display_width = display_width;
+  pTrack->m_display_height = display_height;
+  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
+}
+
+bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
+  return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
+}
+
+long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
+  const long status = GetFirst(pResult);
+
+  if (status < 0)  // buffer underflow, etc
+    return status;
+
+  assert(pResult);
+
+  if (pResult->EOS())
+    return 0;
+
+  const Cluster* pCluster = pResult->GetCluster();
+  assert(pCluster);
+  assert(pCluster->GetIndex() >= 0);
+
+  if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
+    return 0;
+
+  Cluster** const clusters = m_pSegment->m_clusters;
+  assert(clusters);
+
+  const long count = m_pSegment->GetCount();  // loaded only, not pre-loaded
+  assert(count > 0);
+
+  Cluster** const i = clusters + pCluster->GetIndex();
+  assert(i);
+  assert(*i == pCluster);
+  assert(pCluster->GetTime() <= time_ns);
+
+  Cluster** const j = clusters + count;
+
+  Cluster** lo = i;
+  Cluster** hi = j;
+
+  while (lo < hi) {
+    // INVARIANT:
+    //[i, lo) <= time_ns
+    //[lo, hi) ?
+    //[hi, j)  > time_ns
+
+    Cluster** const mid = lo + (hi - lo) / 2;
+    assert(mid < hi);
+
+    pCluster = *mid;
+    assert(pCluster);
+    assert(pCluster->GetIndex() >= 0);
+    assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
+
+    const long long t = pCluster->GetTime();
+
+    if (t <= time_ns)
+      lo = mid + 1;
+    else
+      hi = mid;
+
+    assert(lo <= hi);
+  }
+
+  assert(lo == hi);
+  assert(lo > i);
+  assert(lo <= j);
+
+  pCluster = *--lo;
+  assert(pCluster);
+  assert(pCluster->GetTime() <= time_ns);
+
+  pResult = pCluster->GetEntry(this, time_ns);
+
+  if ((pResult != 0) && !pResult->EOS())  // found a keyframe
+    return 0;
+
+  while (lo != i) {
+    pCluster = *--lo;
+    assert(pCluster);
+    assert(pCluster->GetTime() <= time_ns);
+
+    pResult = pCluster->GetEntry(this, time_ns);
+
+    if ((pResult != 0) && !pResult->EOS())
+      return 0;
+  }
+
+  // weird: we're on the first cluster, but no keyframe found
+  // should never happen but we must return something anyway
+
+  pResult = GetEOS();
+  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; }
+
+long long VideoTrack::GetDisplayWidth() const {
+  return m_display_width > 0 ? m_display_width : GetWidth();
+}
+
+long long VideoTrack::GetDisplayHeight() const {
+  return m_display_height > 0 ? m_display_height : GetHeight();
+}
+
+long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
+
+long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
+
+double VideoTrack::GetFrameRate() const { return m_rate; }
+
+AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
+                       long long element_size)
+    : Track(pSegment, element_start, element_size) {}
+
+long AudioTrack::Parse(Segment* pSegment, const Info& info,
+                       long long element_start, long long element_size,
+                       AudioTrack*& pResult) {
+  if (pResult)
+    return -1;
+
+  if (info.type != Track::kAudio)
+    return -1;
+
+  IMkvReader* const pReader = pSegment->m_pReader;
+
+  const Settings& s = info.settings;
+  assert(s.start >= 0);
+  assert(s.size >= 0);
+
+  long long pos = s.start;
+  assert(pos >= 0);
+
+  const long long stop = pos + s.size;
+
+  double rate = 8000.0;  // MKV default
+  long long channels = 1;
+  long long bit_depth = 0;
+
+  while (pos < stop) {
+    long long id, size;
+
+    long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (id == libwebm::kMkvSamplingFrequency) {
+      status = UnserializeFloat(pReader, pos, size, rate);
+
+      if (status < 0)
+        return status;
+
+      if (rate <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvChannels) {
+      channels = UnserializeUInt(pReader, pos, size);
+
+      if (channels <= 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvBitDepth) {
+      bit_depth = UnserializeUInt(pReader, pos, size);
+
+      if (bit_depth <= 0)
+        return E_FILE_FORMAT_INVALID;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  AudioTrack* const pTrack =
+      new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
+
+  if (pTrack == NULL)
+    return -1;  // generic error
+
+  const int status = info.Copy(pTrack->m_info);
+
+  if (status) {
+    delete pTrack;
+    return status;
+  }
+
+  pTrack->m_rate = rate;
+  pTrack->m_channels = channels;
+  pTrack->m_bitDepth = bit_depth;
+
+  pResult = pTrack;
+  return 0;  // success
+}
+
+double AudioTrack::GetSamplingRate() const { return m_rate; }
+
+long long AudioTrack::GetChannels() const { return m_channels; }
+
+long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
+
+Tracks::Tracks(Segment* pSegment, long long start, long long size_,
+               long long element_start, long long element_size)
+    : m_pSegment(pSegment),
+      m_start(start),
+      m_size(size_),
+      m_element_start(element_start),
+      m_element_size(element_size),
+      m_trackEntries(NULL),
+      m_trackEntriesEnd(NULL) {}
+
+long Tracks::Parse() {
+  assert(m_trackEntries == NULL);
+  assert(m_trackEntriesEnd == NULL);
+
+  const long long stop = m_start + m_size;
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  int count = 0;
+  long long pos = m_start;
+
+  while (pos < stop) {
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size == 0)  // weird
+      continue;
+
+    if (id == libwebm::kMkvTrackEntry)
+      ++count;
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if (count <= 0)
+    return 0;  // success
+
+  m_trackEntries = new (std::nothrow) Track*[count];
+
+  if (m_trackEntries == NULL)
+    return -1;
+
+  m_trackEntriesEnd = m_trackEntries;
+
+  pos = m_start;
+
+  while (pos < stop) {
+    const long long element_start = pos;
+
+    long long id, payload_size;
+
+    const long status =
+        ParseElementHeader(pReader, pos, stop, id, payload_size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (payload_size == 0)  // weird
+      continue;
+
+    const long long payload_stop = pos + payload_size;
+    assert(payload_stop <= stop);  // checked in ParseElement
+
+    const long long element_size = payload_stop - element_start;
+
+    if (id == libwebm::kMkvTrackEntry) {
+      Track*& pTrack = *m_trackEntriesEnd;
+      pTrack = NULL;
+
+      const long status = ParseTrackEntry(pos, payload_size, element_start,
+                                          element_size, pTrack);
+      if (status)
+        return status;
+
+      if (pTrack)
+        ++m_trackEntriesEnd;
+    }
+
+    pos = payload_stop;
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+
+  return 0;  // success
+}
+
+unsigned long Tracks::GetTracksCount() const {
+  const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
+  assert(result >= 0);
+
+  return static_cast<unsigned long>(result);
+}
+
+long Tracks::ParseTrackEntry(long long track_start, long long track_size,
+                             long long element_start, long long element_size,
+                             Track*& pResult) const {
+  if (pResult)
+    return -1;
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = track_start;
+  const long long track_stop = track_start + track_size;
+
+  Track::Info info;
+
+  info.type = 0;
+  info.number = 0;
+  info.uid = 0;
+  info.defaultDuration = 0;
+
+  Track::Settings v;
+  v.start = -1;
+  v.size = -1;
+
+  Track::Settings a;
+  a.start = -1;
+  a.size = -1;
+
+  Track::Settings e;  // content_encodings_settings;
+  e.start = -1;
+  e.size = -1;
+
+  long long lacing = 1;  // default is true
+
+  while (pos < track_stop) {
+    long long id, size;
+
+    const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
+
+    if (status < 0)  // error
+      return status;
+
+    if (size < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    const long long start = pos;
+
+    if (id == libwebm::kMkvVideo) {
+      v.start = start;
+      v.size = size;
+    } else if (id == libwebm::kMkvAudio) {
+      a.start = start;
+      a.size = size;
+    } else if (id == libwebm::kMkvContentEncodings) {
+      e.start = start;
+      e.size = size;
+    } else if (id == libwebm::kMkvTrackUID) {
+      if (size > 8)
+        return E_FILE_FORMAT_INVALID;
+
+      info.uid = 0;
+
+      long long pos_ = start;
+      const long long pos_end = start + size;
+
+      while (pos_ != pos_end) {
+        unsigned char b;
+
+        const int status = pReader->Read(pos_, 1, &b);
+
+        if (status)
+          return status;
+
+        info.uid <<= 8;
+        info.uid |= b;
+
+        ++pos_;
+      }
+    } 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 == 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 == libwebm::kMkvName) {
+      const long status =
+          UnserializeString(pReader, pos, size, info.nameAsUTF8);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvLanguage) {
+      const long status = UnserializeString(pReader, pos, size, info.language);
+
+      if (status)
+        return status;
+    } 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 == libwebm::kMkvCodecID) {
+      const long status = UnserializeString(pReader, pos, size, info.codecId);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvFlagLacing) {
+      lacing = UnserializeUInt(pReader, pos, size);
+
+      if ((lacing < 0) || (lacing > 1))
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvCodecPrivate) {
+      delete[] info.codecPrivate;
+      info.codecPrivate = NULL;
+      info.codecPrivateSize = 0;
+
+      const size_t buflen = static_cast<size_t>(size);
+
+      if (buflen) {
+        unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
+
+        if (buf == NULL)
+          return -1;
+
+        const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
+
+        if (status) {
+          delete[] buf;
+          return status;
+        }
+
+        info.codecPrivate = buf;
+        info.codecPrivateSize = buflen;
+      }
+    } else if (id == libwebm::kMkvCodecName) {
+      const long status =
+          UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
+
+      if (status)
+        return status;
+    } else if (id == libwebm::kMkvCodecDelay) {
+      info.codecDelay = UnserializeUInt(pReader, pos, size);
+    } else if (id == libwebm::kMkvSeekPreRoll) {
+      info.seekPreRoll = UnserializeUInt(pReader, pos, size);
+    }
+
+    pos += size;  // consume payload
+    if (pos > track_stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != track_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if (info.number <= 0)  // not specified
+    return E_FILE_FORMAT_INVALID;
+
+  if (GetTrackByNumber(info.number))
+    return E_FILE_FORMAT_INVALID;
+
+  if (info.type <= 0)  // not specified
+    return E_FILE_FORMAT_INVALID;
+
+  info.lacing = (lacing > 0) ? true : false;
+
+  if (info.type == Track::kVideo) {
+    if (v.start < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (a.start >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    info.settings = v;
+
+    VideoTrack* pTrack = NULL;
+
+    const long status = VideoTrack::Parse(m_pSegment, info, element_start,
+                                          element_size, pTrack);
+
+    if (status)
+      return status;
+
+    pResult = pTrack;
+    assert(pResult);
+
+    if (e.start >= 0)
+      pResult->ParseContentEncodingsEntry(e.start, e.size);
+  } else if (info.type == Track::kAudio) {
+    if (a.start < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (v.start >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    info.settings = a;
+
+    AudioTrack* pTrack = NULL;
+
+    const long status = AudioTrack::Parse(m_pSegment, info, element_start,
+                                          element_size, pTrack);
+
+    if (status)
+      return status;
+
+    pResult = pTrack;
+    assert(pResult);
+
+    if (e.start >= 0)
+      pResult->ParseContentEncodingsEntry(e.start, e.size);
+  } else {
+    // neither video nor audio - probably metadata or subtitles
+
+    if (a.start >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (v.start >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (info.type == Track::kMetadata && e.start >= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    info.settings.start = -1;
+    info.settings.size = 0;
+
+    Track* pTrack = NULL;
+
+    const long status =
+        Track::Create(m_pSegment, info, element_start, element_size, pTrack);
+
+    if (status)
+      return status;
+
+    pResult = pTrack;
+    assert(pResult);
+  }
+
+  return 0;  // success
+}
+
+Tracks::~Tracks() {
+  Track** i = m_trackEntries;
+  Track** const j = m_trackEntriesEnd;
+
+  while (i != j) {
+    Track* const pTrack = *i++;
+    delete pTrack;
+  }
+
+  delete[] m_trackEntries;
+}
+
+const Track* Tracks::GetTrackByNumber(long tn) const {
+  if (tn < 0)
+    return NULL;
+
+  Track** i = m_trackEntries;
+  Track** const j = m_trackEntriesEnd;
+
+  while (i != j) {
+    Track* const pTrack = *i++;
+
+    if (pTrack == NULL)
+      continue;
+
+    if (tn == pTrack->GetNumber())
+      return pTrack;
+  }
+
+  return NULL;  // not found
+}
+
+const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
+  const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
+
+  if (idx >= static_cast<unsigned long>(count))
+    return NULL;
+
+  return m_trackEntries[idx];
+}
+
+long Cluster::Load(long long& pos, long& len) const {
+  if (m_pSegment == NULL)
+    return E_PARSE_FAILED;
+
+  if (m_timecode >= 0)  // at least partially loaded
+    return 0;
+
+  if (m_pos != m_element_start || m_element_size >= 0)
+    return E_PARSE_FAILED;
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+  long long total, avail;
+  const int status = pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  if (total >= 0 && (avail > total || m_pos > total))
+    return E_FILE_FORMAT_INVALID;
+
+  pos = m_pos;
+
+  long long cluster_size = -1;
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  long long result = GetUIntLength(pReader, pos, len);
+
+  if (result < 0)  // error or underflow
+    return static_cast<long>(result);
+
+  if (result > 0)
+    return E_BUFFER_NOT_FULL;
+
+  if ((pos + len) > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long id_ = ReadID(pReader, pos, len);
+
+  if (id_ < 0)  // error
+    return static_cast<long>(id_);
+
+  if (id_ != libwebm::kMkvCluster)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume id
+
+  // read cluster size
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  result = GetUIntLength(pReader, pos, len);
+
+  if (result < 0)  // error
+    return static_cast<long>(result);
+
+  if (result > 0)
+    return E_BUFFER_NOT_FULL;
+
+  if ((pos + len) > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long size = ReadUInt(pReader, pos, len);
+
+  if (size < 0)  // error
+    return static_cast<long>(cluster_size);
+
+  if (size == 0)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume length of size of element
+
+  const long long unknown_size = (1LL << (7 * len)) - 1;
+
+  if (size != unknown_size)
+    cluster_size = size;
+
+  // pos points to start of payload
+  long long timecode = -1;
+  long long new_pos = -1;
+  bool bBlock = false;
+
+  long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
+
+  for (;;) {
+    if ((cluster_stop >= 0) && (pos >= cluster_stop))
+      break;
+
+    // Parse ID
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)  // error
+      return static_cast<long>(id);
+
+    if (id == 0)
+      return E_FILE_FORMAT_INVALID;
+
+    // This is the distinguished set of ID's we use to determine
+    // that we have exhausted the sub-element's inside the cluster
+    // whose ID we parsed earlier.
+
+    if (id == libwebm::kMkvCluster)
+      break;
+
+    if (id == libwebm::kMkvCues)
+      break;
+
+    pos += len;  // consume ID field
+
+    // Parse Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size == unknown_size)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume size field
+
+    if ((cluster_stop >= 0) && (pos > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    // pos now points to start of payload
+
+    if (size == 0)
+      continue;
+
+    if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if (id == libwebm::kMkvTimecode) {
+      len = static_cast<long>(size);
+
+      if ((pos + size) > avail)
+        return E_BUFFER_NOT_FULL;
+
+      timecode = UnserializeUInt(pReader, pos, size);
+
+      if (timecode < 0)  // error (or underflow)
+        return static_cast<long>(timecode);
+
+      new_pos = pos + size;
+
+      if (bBlock)
+        break;
+    } else if (id == libwebm::kMkvBlockGroup) {
+      bBlock = true;
+      break;
+    } else if (id == libwebm::kMkvSimpleBlock) {
+      bBlock = true;
+      break;
+    }
+
+    pos += size;  // consume payload
+    if (cluster_stop >= 0 && pos > cluster_stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (cluster_stop >= 0 && pos > cluster_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if (timecode < 0)  // no timecode found
+    return E_FILE_FORMAT_INVALID;
+
+  if (!bBlock)
+    return E_FILE_FORMAT_INVALID;
+
+  m_pos = new_pos;  // designates position just beyond timecode payload
+  m_timecode = timecode;  // m_timecode >= 0 means we're partially loaded
+
+  if (cluster_size >= 0)
+    m_element_size = cluster_stop - m_element_start;
+
+  return 0;
+}
+
+long Cluster::Parse(long long& pos, long& len) const {
+  long status = Load(pos, len);
+
+  if (status < 0)
+    return status;
+
+  if (m_pos < m_element_start || m_timecode < 0)
+    return E_PARSE_FAILED;
+
+  const long long cluster_stop =
+      (m_element_size < 0) ? -1 : m_element_start + m_element_size;
+
+  if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
+    return 1;  // nothing else to do
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long total, avail;
+
+  status = pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  if (total >= 0 && avail > total)
+    return E_FILE_FORMAT_INVALID;
+
+  pos = m_pos;
+
+  for (;;) {
+    if ((cluster_stop >= 0) && (pos >= cluster_stop))
+      break;
+
+    if ((total >= 0) && (pos >= total)) {
+      if (m_element_size < 0)
+        m_element_size = pos - m_element_start;
+
+      break;
+    }
+
+    // Parse ID
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)
+      return E_FILE_FORMAT_INVALID;
+
+    // This is the distinguished set of ID's we use to determine
+    // that we have exhausted the sub-element's inside the cluster
+    // whose ID we parsed earlier.
+
+    if ((id == libwebm::kMkvCluster) || (id == libwebm::kMkvCues)) {
+      if (m_element_size < 0)
+        m_element_size = pos - m_element_start;
+
+      break;
+    }
+
+    pos += len;  // consume ID field
+
+    // Parse Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size == unknown_size)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume size field
+
+    if ((cluster_stop >= 0) && (pos > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    // pos now points to start of payload
+
+    if (size == 0)
+      continue;
+
+    // const long long block_start = pos;
+    const long long block_stop = pos + size;
+
+    if (cluster_stop >= 0) {
+      if (block_stop > cluster_stop) {
+        if (id == libwebm::kMkvBlockGroup || id == libwebm::kMkvSimpleBlock) {
+          return E_FILE_FORMAT_INVALID;
+        }
+
+        pos = cluster_stop;
+        break;
+      }
+    } else if ((total >= 0) && (block_stop > total)) {
+      m_element_size = total - m_element_start;
+      pos = total;
+      break;
+    } else if (block_stop > avail) {
+      len = static_cast<long>(size);
+      return E_BUFFER_NOT_FULL;
+    }
+
+    Cluster* const this_ = const_cast<Cluster*>(this);
+
+    if (id == libwebm::kMkvBlockGroup)
+      return this_->ParseBlockGroup(size, pos, len);
+
+    if (id == libwebm::kMkvSimpleBlock)
+      return this_->ParseSimpleBlock(size, pos, len);
+
+    pos += size;  // consume payload
+    if (cluster_stop >= 0 && pos > cluster_stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (m_element_size < 1)
+    return E_FILE_FORMAT_INVALID;
+
+  m_pos = pos;
+  if (cluster_stop >= 0 && m_pos > cluster_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if (m_entries_count > 0) {
+    const long idx = m_entries_count - 1;
+
+    const BlockEntry* const pLast = m_entries[idx];
+    if (pLast == NULL)
+      return E_PARSE_FAILED;
+
+    const Block* const pBlock = pLast->GetBlock();
+    if (pBlock == NULL)
+      return E_PARSE_FAILED;
+
+    const long long start = pBlock->m_start;
+
+    if ((total >= 0) && (start > total))
+      return E_PARSE_FAILED;  // defend against trucated stream
+
+    const long long size = pBlock->m_size;
+
+    const long long stop = start + size;
+    if (cluster_stop >= 0 && stop > cluster_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((total >= 0) && (stop > total))
+      return E_PARSE_FAILED;  // defend against trucated stream
+  }
+
+  return 1;  // no more entries
+}
+
+long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
+                               long& len) {
+  const long long block_start = pos;
+  const long long block_stop = pos + block_size;
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long total, avail;
+
+  long status = pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  // parse track number
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  long long result = GetUIntLength(pReader, pos, len);
+
+  if (result < 0)  // error
+    return static_cast<long>(result);
+
+  if (result > 0)  // weird
+    return E_BUFFER_NOT_FULL;
+
+  if ((pos + len) > block_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + len) > avail)
+    return E_BUFFER_NOT_FULL;
+
+  const long long track = ReadUInt(pReader, pos, len);
+
+  if (track < 0)  // error
+    return static_cast<long>(track);
+
+  if (track == 0)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume track number
+
+  if ((pos + 2) > block_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + 2) > avail) {
+    len = 2;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  pos += 2;  // consume timecode
+
+  if ((pos + 1) > block_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + 1) > avail) {
+    len = 1;
+    return E_BUFFER_NOT_FULL;
+  }
+
+  unsigned char flags;
+
+  status = pReader->Read(pos, 1, &flags);
+
+  if (status < 0) {  // error or underflow
+    len = 1;
+    return status;
+  }
+
+  ++pos;  // consume flags byte
+  assert(pos <= avail);
+
+  if (pos >= block_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  const int lacing = int(flags & 0x06) >> 1;
+
+  if ((lacing != 0) && (block_stop > avail)) {
+    len = static_cast<long>(block_stop - pos);
+    return E_BUFFER_NOT_FULL;
+  }
+
+  status = CreateBlock(libwebm::kMkvSimpleBlock, block_start, block_size,
+                       0);  // DiscardPadding
+
+  if (status != 0)
+    return status;
+
+  m_pos = block_stop;
+
+  return 0;  // success
+}
+
+long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
+                              long& len) {
+  const long long payload_start = pos;
+  const long long payload_stop = pos + payload_size;
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long total, avail;
+
+  long status = pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  if ((total >= 0) && (payload_stop > total))
+    return E_FILE_FORMAT_INVALID;
+
+  if (payload_stop > avail) {
+    len = static_cast<long>(payload_size);
+    return E_BUFFER_NOT_FULL;
+  }
+
+  long long discard_padding = 0;
+
+  while (pos < payload_stop) {
+    // parse sub-block element ID
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((pos + len) > payload_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)  // error
+      return static_cast<long>(id);
+
+    if (id == 0)  // not a valid ID
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume ID field
+
+    // Parse Size
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((pos + len) > payload_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    pos += len;  // consume size field
+
+    // pos now points to start of sub-block group payload
+
+    if (pos > payload_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if (size == 0)  // weird
+      continue;
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size == unknown_size)
+      return E_FILE_FORMAT_INVALID;
+
+    if (id == libwebm::kMkvDiscardPadding) {
+      status = UnserializeInt(pReader, pos, size, discard_padding);
+
+      if (status < 0)  // error
+        return status;
+    }
+
+    if (id != libwebm::kMkvBlock) {
+      pos += size;  // consume sub-part of block group
+
+      if (pos > payload_stop)
+        return E_FILE_FORMAT_INVALID;
+
+      continue;
+    }
+
+    const long long block_stop = pos + size;
+
+    if (block_stop > payload_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    // parse track number
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((pos + len) > block_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long track = ReadUInt(pReader, pos, len);
+
+    if (track < 0)  // error
+      return static_cast<long>(track);
+
+    if (track == 0)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume track number
+
+    if ((pos + 2) > block_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + 2) > avail) {
+      len = 2;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    pos += 2;  // consume timecode
+
+    if ((pos + 1) > block_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    unsigned char flags;
+
+    status = pReader->Read(pos, 1, &flags);
+
+    if (status < 0) {  // error or underflow
+      len = 1;
+      return status;
+    }
+
+    ++pos;  // consume flags byte
+    assert(pos <= avail);
+
+    if (pos >= block_stop)
+      return E_FILE_FORMAT_INVALID;
+
+    const int lacing = int(flags & 0x06) >> 1;
+
+    if ((lacing != 0) && (block_stop > avail)) {
+      len = static_cast<long>(block_stop - pos);
+      return E_BUFFER_NOT_FULL;
+    }
+
+    pos = block_stop;  // consume block-part of block group
+    if (pos > payload_stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  if (pos != payload_stop)
+    return E_FILE_FORMAT_INVALID;
+
+  status = CreateBlock(libwebm::kMkvBlockGroup, payload_start, payload_size,
+                       discard_padding);
+  if (status != 0)
+    return status;
+
+  m_pos = payload_stop;
+
+  return 0;  // success
+}
+
+long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
+  assert(m_pos >= m_element_start);
+
+  pEntry = NULL;
+
+  if (index < 0)
+    return -1;  // generic error
+
+  if (m_entries_count < 0)
+    return E_BUFFER_NOT_FULL;
+
+  assert(m_entries);
+  assert(m_entries_size > 0);
+  assert(m_entries_count <= m_entries_size);
+
+  if (index < m_entries_count) {
+    pEntry = m_entries[index];
+    assert(pEntry);
+
+    return 1;  // found entry
+  }
+
+  if (m_element_size < 0)  // we don't know cluster end yet
+    return E_BUFFER_NOT_FULL;  // underflow
+
+  const long long element_stop = m_element_start + m_element_size;
+
+  if (m_pos >= element_stop)
+    return 0;  // nothing left to parse
+
+  return E_BUFFER_NOT_FULL;  // underflow, since more remains to be parsed
+}
+
+Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
+  if (!pSegment || off < 0)
+    return NULL;
+
+  const long long element_start = pSegment->m_start + off;
+
+  Cluster* const pCluster =
+      new (std::nothrow) Cluster(pSegment, idx, element_start);
+
+  return pCluster;
+}
+
+Cluster::Cluster()
+    : m_pSegment(NULL),
+      m_element_start(0),
+      m_index(0),
+      m_pos(0),
+      m_element_size(0),
+      m_timecode(0),
+      m_entries(NULL),
+      m_entries_size(0),
+      m_entries_count(0)  // means "no entries"
+{}
+
+Cluster::Cluster(Segment* pSegment, long idx, long long element_start
+                 /* long long element_size */)
+    : m_pSegment(pSegment),
+      m_element_start(element_start),
+      m_index(idx),
+      m_pos(element_start),
+      m_element_size(-1 /* element_size */),
+      m_timecode(-1),
+      m_entries(NULL),
+      m_entries_size(0),
+      m_entries_count(-1)  // means "has not been parsed yet"
+{}
+
+Cluster::~Cluster() {
+  if (m_entries_count <= 0)
+    return;
+
+  BlockEntry** i = m_entries;
+  BlockEntry** const j = m_entries + m_entries_count;
+
+  while (i != j) {
+    BlockEntry* p = *i++;
+    assert(p);
+
+    delete p;
+  }
+
+  delete[] m_entries;
+}
+
+bool Cluster::EOS() const { return (m_pSegment == NULL); }
+
+long Cluster::GetIndex() const { return m_index; }
+
+long long Cluster::GetPosition() const {
+  const long long pos = m_element_start - m_pSegment->m_start;
+  assert(pos >= 0);
+
+  return pos;
+}
+
+long long Cluster::GetElementSize() const { return m_element_size; }
+
+long Cluster::HasBlockEntries(
+    const Segment* pSegment,
+    long long off,  // relative to start of segment payload
+    long long& pos, long& len) {
+  assert(pSegment);
+  assert(off >= 0);  // relative to segment
+
+  IMkvReader* const pReader = pSegment->m_pReader;
+
+  long long total, avail;
+
+  long status = pReader->Length(&total, &avail);
+
+  if (status < 0)  // error
+    return status;
+
+  assert((total < 0) || (avail <= total));
+
+  pos = pSegment->m_start + off;  // absolute
+
+  if ((total >= 0) && (pos >= total))
+    return 0;  // we don't even have a complete cluster
+
+  const long long segment_stop =
+      (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
+
+  long long cluster_stop = -1;  // interpreted later to mean "unknown size"
+
+  {
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // need more data
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((total >= 0) && ((pos + len) > total))
+      return 0;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)  // error
+      return static_cast<long>(id);
+
+    if (id != libwebm::kMkvCluster)
+      return E_PARSE_FAILED;
+
+    pos += len;  // consume Cluster ID field
+
+    // read size field
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // weird
+      return E_BUFFER_NOT_FULL;
+
+    if ((segment_stop >= 0) && ((pos + len) > segment_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((total >= 0) && ((pos + len) > total))
+      return 0;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    if (size == 0)
+      return 0;  // cluster does not have entries
+
+    pos += len;  // consume size field
+
+    // pos now points to start of payload
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size != unknown_size) {
+      cluster_stop = pos + size;
+      assert(cluster_stop >= 0);
+
+      if ((segment_stop >= 0) && (cluster_stop > segment_stop))
+        return E_FILE_FORMAT_INVALID;
+
+      if ((total >= 0) && (cluster_stop > total))
+        // return E_FILE_FORMAT_INVALID;  //too conservative
+        return 0;  // cluster does not have any entries
+    }
+  }
+
+  for (;;) {
+    if ((cluster_stop >= 0) && (pos >= cluster_stop))
+      return 0;  // no entries detected
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    long long result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // need more data
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long id = ReadID(pReader, pos, len);
+
+    if (id < 0)  // error
+      return static_cast<long>(id);
+
+    // This is the distinguished set of ID's we use to determine
+    // that we have exhausted the sub-element's inside the cluster
+    // whose ID we parsed earlier.
+
+    if (id == libwebm::kMkvCluster)
+      return 0;  // no entries found
+
+    if (id == libwebm::kMkvCues)
+      return 0;  // no entries found
+
+    pos += len;  // consume id field
+
+    if ((cluster_stop >= 0) && (pos >= cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    // read size field
+
+    if ((pos + 1) > avail) {
+      len = 1;
+      return E_BUFFER_NOT_FULL;
+    }
+
+    result = GetUIntLength(pReader, pos, len);
+
+    if (result < 0)  // error
+      return static_cast<long>(result);
+
+    if (result > 0)  // underflow
+      return E_BUFFER_NOT_FULL;
+
+    if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > avail)
+      return E_BUFFER_NOT_FULL;
+
+    const long long size = ReadUInt(pReader, pos, len);
+
+    if (size < 0)  // error
+      return static_cast<long>(size);
+
+    pos += len;  // consume size field
+
+    // pos now points to start of payload
+
+    if ((cluster_stop >= 0) && (pos > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if (size == 0)  // weird
+      continue;
+
+    const long long unknown_size = (1LL << (7 * len)) - 1;
+
+    if (size == unknown_size)
+      return E_FILE_FORMAT_INVALID;  // not supported inside cluster
+
+    if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
+      return E_FILE_FORMAT_INVALID;
+
+    if (id == libwebm::kMkvBlockGroup)
+      return 1;  // have at least one entry
+
+    if (id == libwebm::kMkvSimpleBlock)
+      return 1;  // have at least one entry
+
+    pos += size;  // consume payload
+    if (cluster_stop >= 0 && pos > cluster_stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+}
+
+long long Cluster::GetTimeCode() const {
+  long long pos;
+  long len;
+
+  const long status = Load(pos, len);
+
+  if (status < 0)  // error
+    return status;
+
+  return m_timecode;
+}
+
+long long Cluster::GetTime() const {
+  const long long tc = GetTimeCode();
+
+  if (tc < 0)
+    return tc;
+
+  const SegmentInfo* const pInfo = m_pSegment->GetInfo();
+  assert(pInfo);
+
+  const long long scale = pInfo->GetTimeCodeScale();
+  assert(scale >= 1);
+
+  const long long t = m_timecode * scale;
+
+  return t;
+}
+
+long long Cluster::GetFirstTime() const {
+  const BlockEntry* pEntry;
+
+  const long status = GetFirst(pEntry);
+
+  if (status < 0)  // error
+    return status;
+
+  if (pEntry == NULL)  // empty cluster
+    return GetTime();
+
+  const Block* const pBlock = pEntry->GetBlock();
+  assert(pBlock);
+
+  return pBlock->GetTime(this);
+}
+
+long long Cluster::GetLastTime() const {
+  const BlockEntry* pEntry;
+
+  const long status = GetLast(pEntry);
+
+  if (status < 0)  // error
+    return status;
+
+  if (pEntry == NULL)  // empty cluster
+    return GetTime();
+
+  const Block* const pBlock = pEntry->GetBlock();
+  assert(pBlock);
+
+  return pBlock->GetTime(this);
+}
+
+long Cluster::CreateBlock(long long id,
+                          long long pos,  // absolute pos of payload
+                          long long size, long long discard_padding) {
+  if (id != libwebm::kMkvBlockGroup && id != libwebm::kMkvSimpleBlock)
+    return E_PARSE_FAILED;
+
+  if (m_entries_count < 0) {  // haven't parsed anything yet
+    assert(m_entries == NULL);
+    assert(m_entries_size == 0);
+
+    m_entries_size = 1024;
+    m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
+    if (m_entries == NULL)
+      return -1;
+
+    m_entries_count = 0;
+  } else {
+    assert(m_entries);
+    assert(m_entries_size > 0);
+    assert(m_entries_count <= m_entries_size);
+
+    if (m_entries_count >= m_entries_size) {
+      const long entries_size = 2 * m_entries_size;
+
+      BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
+      if (entries == NULL)
+        return -1;
+
+      BlockEntry** src = m_entries;
+      BlockEntry** const src_end = src + m_entries_count;
+
+      BlockEntry** dst = entries;
+
+      while (src != src_end)
+        *dst++ = *src++;
+
+      delete[] m_entries;
+
+      m_entries = entries;
+      m_entries_size = entries_size;
+    }
+  }
+
+  if (id == libwebm::kMkvBlockGroup)
+    return CreateBlockGroup(pos, size, discard_padding);
+  else
+    return CreateSimpleBlock(pos, size);
+}
+
+long Cluster::CreateBlockGroup(long long start_offset, long long size,
+                               long long discard_padding) {
+  assert(m_entries);
+  assert(m_entries_size > 0);
+  assert(m_entries_count >= 0);
+  assert(m_entries_count < m_entries_size);
+
+  IMkvReader* const pReader = m_pSegment->m_pReader;
+
+  long long pos = start_offset;
+  const long long stop = start_offset + size;
+
+  // For WebM files, there is a bias towards previous reference times
+  //(in order to support alt-ref frames, which refer back to the previous
+  // keyframe).  Normally a 0 value is not possible, but here we tenatively
+  // allow 0 as the value of a reference frame, with the interpretation
+  // that this is a "previous" reference time.
+
+  long long prev = 1;  // nonce
+  long long next = 0;  // nonce
+  long long duration = -1;  // really, this is unsigned
+
+  long long bpos = -1;
+  long long bsize = -1;
+
+  while (pos < stop) {
+    long len;
+    const long long id = ReadID(pReader, pos, len);
+    if (id < 0 || (pos + len) > stop)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume ID
+
+    const long long size = ReadUInt(pReader, pos, len);
+    assert(size >= 0);  // TODO
+    assert((pos + len) <= stop);
+
+    pos += len;  // consume size
+
+    if (id == libwebm::kMkvBlock) {
+      if (bpos < 0) {  // Block ID
+        bpos = pos;
+        bsize = size;
+      }
+    } else if (id == libwebm::kMkvBlockDuration) {
+      if (size > 8)
+        return E_FILE_FORMAT_INVALID;
+
+      duration = UnserializeUInt(pReader, pos, size);
+
+      if (duration < 0)
+        return E_FILE_FORMAT_INVALID;
+    } else if (id == libwebm::kMkvReferenceBlock) {
+      if (size > 8 || size <= 0)
+        return E_FILE_FORMAT_INVALID;
+      const long size_ = static_cast<long>(size);
+
+      long long time;
+
+      long status = UnserializeInt(pReader, pos, size_, time);
+      assert(status == 0);
+      if (status != 0)
+        return -1;
+
+      if (time <= 0)  // see note above
+        prev = time;
+      else
+        next = time;
+    }
+
+    pos += size;  // consume payload
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+  if (bpos < 0)
+    return E_FILE_FORMAT_INVALID;
+
+  if (pos != stop)
+    return E_FILE_FORMAT_INVALID;
+  assert(bsize >= 0);
+
+  const long idx = m_entries_count;
+
+  BlockEntry** const ppEntry = m_entries + idx;
+  BlockEntry*& pEntry = *ppEntry;
+
+  pEntry = new (std::nothrow)
+      BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
+
+  if (pEntry == NULL)
+    return -1;  // generic error
+
+  BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
+
+  const long status = p->Parse();
+
+  if (status == 0) {  // success
+    ++m_entries_count;
+    return 0;
+  }
+
+  delete pEntry;
+  pEntry = 0;
+
+  return status;
+}
+
+long Cluster::CreateSimpleBlock(long long st, long long sz) {
+  assert(m_entries);
+  assert(m_entries_size > 0);
+  assert(m_entries_count >= 0);
+  assert(m_entries_count < m_entries_size);
+
+  const long idx = m_entries_count;
+
+  BlockEntry** const ppEntry = m_entries + idx;
+  BlockEntry*& pEntry = *ppEntry;
+
+  pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
+
+  if (pEntry == NULL)
+    return -1;  // generic error
+
+  SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
+
+  const long status = p->Parse();
+
+  if (status == 0) {
+    ++m_entries_count;
+    return 0;
+  }
+
+  delete pEntry;
+  pEntry = 0;
+
+  return status;
+}
+
+long Cluster::GetFirst(const BlockEntry*& pFirst) const {
+  if (m_entries_count <= 0) {
+    long long pos;
+    long len;
+
+    const long status = Parse(pos, len);
+
+    if (status < 0) {  // error
+      pFirst = NULL;
+      return status;
+    }
+
+    if (m_entries_count <= 0) {  // empty cluster
+      pFirst = NULL;
+      return 0;
+    }
+  }
+
+  assert(m_entries);
+
+  pFirst = m_entries[0];
+  assert(pFirst);
+
+  return 0;  // success
+}
+
+long Cluster::GetLast(const BlockEntry*& pLast) const {
+  for (;;) {
+    long long pos;
+    long len;
+
+    const long status = Parse(pos, len);
+
+    if (status < 0) {  // error
+      pLast = NULL;
+      return status;
+    }
+
+    if (status > 0)  // no new block
+      break;
+  }
+
+  if (m_entries_count <= 0) {
+    pLast = NULL;
+    return 0;
+  }
+
+  assert(m_entries);
+
+  const long idx = m_entries_count - 1;
+
+  pLast = m_entries[idx];
+  assert(pLast);
+
+  return 0;
+}
+
+long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
+  assert(pCurr);
+  assert(m_entries);
+  assert(m_entries_count > 0);
+
+  size_t idx = pCurr->GetIndex();
+  assert(idx < size_t(m_entries_count));
+  assert(m_entries[idx] == pCurr);
+
+  ++idx;
+
+  if (idx >= size_t(m_entries_count)) {
+    long long pos;
+    long len;
+
+    const long status = Parse(pos, len);
+
+    if (status < 0) {  // error
+      pNext = NULL;
+      return status;
+    }
+
+    if (status > 0) {
+      pNext = NULL;
+      return 0;
+    }
+
+    assert(m_entries);
+    assert(m_entries_count > 0);
+    assert(idx < size_t(m_entries_count));
+  }
+
+  pNext = m_entries[idx];
+  assert(pNext);
+
+  return 0;
+}
+
+long Cluster::GetEntryCount() const { return m_entries_count; }
+
+const BlockEntry* Cluster::GetEntry(const Track* pTrack,
+                                    long long time_ns) const {
+  assert(pTrack);
+
+  if (m_pSegment == NULL)  // this is the special EOS cluster
+    return pTrack->GetEOS();
+
+  const BlockEntry* pResult = pTrack->GetEOS();
+
+  long index = 0;
+
+  for (;;) {
+    if (index >= m_entries_count) {
+      long long pos;
+      long len;
+
+      const long status = Parse(pos, len);
+      assert(status >= 0);
+
+      if (status > 0)  // completely parsed, and no more entries
+        return pResult;
+
+      if (status < 0)  // should never happen
+        return 0;
+
+      assert(m_entries);
+      assert(index < m_entries_count);
+    }
+
+    const BlockEntry* const pEntry = m_entries[index];
+    assert(pEntry);
+    assert(!pEntry->EOS());
+
+    const Block* const pBlock = pEntry->GetBlock();
+    assert(pBlock);
+
+    if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
+      ++index;
+      continue;
+    }
+
+    if (pTrack->VetEntry(pEntry)) {
+      if (time_ns < 0)  // just want first candidate block
+        return pEntry;
+
+      const long long ns = pBlock->GetTime(this);
+
+      if (ns > time_ns)
+        return pResult;
+
+      pResult = pEntry;  // have a candidate
+    } else if (time_ns >= 0) {
+      const long long ns = pBlock->GetTime(this);
+
+      if (ns > time_ns)
+        return pResult;
+    }
+
+    ++index;
+  }
+}
+
+const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
+                                    const CuePoint::TrackPosition& tp) const {
+  assert(m_pSegment);
+  const long long tc = cp.GetTimeCode();
+
+  if (tp.m_block > 0) {
+    const long block = static_cast<long>(tp.m_block);
+    const long index = block - 1;
+
+    while (index >= m_entries_count) {
+      long long pos;
+      long len;
+
+      const long status = Parse(pos, len);
+
+      if (status < 0)  // TODO: can this happen?
+        return NULL;
+
+      if (status > 0)  // nothing remains to be parsed
+        return NULL;
+    }
+
+    const BlockEntry* const pEntry = m_entries[index];
+    assert(pEntry);
+    assert(!pEntry->EOS());
+
+    const Block* const pBlock = pEntry->GetBlock();
+    assert(pBlock);
+
+    if ((pBlock->GetTrackNumber() == tp.m_track) &&
+        (pBlock->GetTimeCode(this) == tc)) {
+      return pEntry;
+    }
+  }
+
+  long index = 0;
+
+  for (;;) {
+    if (index >= m_entries_count) {
+      long long pos;
+      long len;
+
+      const long status = Parse(pos, len);
+
+      if (status < 0)  // TODO: can this happen?
+        return NULL;
+
+      if (status > 0)  // nothing remains to be parsed
+        return NULL;
+
+      assert(m_entries);
+      assert(index < m_entries_count);
+    }
+
+    const BlockEntry* const pEntry = m_entries[index];
+    assert(pEntry);
+    assert(!pEntry->EOS());
+
+    const Block* const pBlock = pEntry->GetBlock();
+    assert(pBlock);
+
+    if (pBlock->GetTrackNumber() != tp.m_track) {
+      ++index;
+      continue;
+    }
+
+    const long long tc_ = pBlock->GetTimeCode(this);
+
+    if (tc_ < tc) {
+      ++index;
+      continue;
+    }
+
+    if (tc_ > tc)
+      return NULL;
+
+    const Tracks* const pTracks = m_pSegment->GetTracks();
+    assert(pTracks);
+
+    const long tn = static_cast<long>(tp.m_track);
+    const Track* const pTrack = pTracks->GetTrackByNumber(tn);
+
+    if (pTrack == NULL)
+      return NULL;
+
+    const long long type = pTrack->GetType();
+
+    if (type == 2)  // audio
+      return pEntry;
+
+    if (type != 1)  // not video
+      return NULL;
+
+    if (!pBlock->IsKey())
+      return NULL;
+
+    return pEntry;
+  }
+}
+
+BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
+BlockEntry::~BlockEntry() {}
+const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
+long BlockEntry::GetIndex() const { return m_index; }
+
+SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
+                         long long size)
+    : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
+
+long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
+BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
+const Block* SimpleBlock::GetBlock() const { return &m_block; }
+
+BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
+                       long long block_size, long long prev, long long next,
+                       long long duration, long long discard_padding)
+    : BlockEntry(pCluster, idx),
+      m_block(block_start, block_size, discard_padding),
+      m_prev(prev),
+      m_next(next),
+      m_duration(duration) {}
+
+long BlockGroup::Parse() {
+  const long status = m_block.Parse(m_pCluster);
+
+  if (status)
+    return status;
+
+  m_block.SetKey((m_prev > 0) && (m_next <= 0));
+
+  return 0;
+}
+
+BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
+const Block* BlockGroup::GetBlock() const { return &m_block; }
+long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
+long long BlockGroup::GetNextTimeCode() const { return m_next; }
+long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
+
+Block::Block(long long start, long long size_, long long discard_padding)
+    : m_start(start),
+      m_size(size_),
+      m_track(0),
+      m_timecode(-1),
+      m_flags(0),
+      m_frames(NULL),
+      m_frame_count(-1),
+      m_discard_padding(discard_padding) {}
+
+Block::~Block() { delete[] m_frames; }
+
+long Block::Parse(const Cluster* pCluster) {
+  if (pCluster == NULL)
+    return -1;
+
+  if (pCluster->m_pSegment == NULL)
+    return -1;
+
+  assert(m_start >= 0);
+  assert(m_size >= 0);
+  assert(m_track <= 0);
+  assert(m_frames == NULL);
+  assert(m_frame_count <= 0);
+
+  long long pos = m_start;
+  const long long stop = m_start + m_size;
+
+  long len;
+
+  IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
+
+  m_track = ReadUInt(pReader, pos, len);
+
+  if (m_track <= 0)
+    return E_FILE_FORMAT_INVALID;
+
+  if ((pos + len) > stop)
+    return E_FILE_FORMAT_INVALID;
+
+  pos += len;  // consume track number
+
+  if ((stop - pos) < 2)
+    return E_FILE_FORMAT_INVALID;
+
+  long status;
+  long long value;
+
+  status = UnserializeInt(pReader, pos, 2, value);
+
+  if (status)
+    return E_FILE_FORMAT_INVALID;
+
+  if (value < SHRT_MIN)
+    return E_FILE_FORMAT_INVALID;
+
+  if (value > SHRT_MAX)
+    return E_FILE_FORMAT_INVALID;
+
+  m_timecode = static_cast<short>(value);
+
+  pos += 2;
+
+  if ((stop - pos) <= 0)
+    return E_FILE_FORMAT_INVALID;
+
+  status = pReader->Read(pos, 1, &m_flags);
+
+  if (status)
+    return E_FILE_FORMAT_INVALID;
+
+  const int lacing = int(m_flags & 0x06) >> 1;
+
+  ++pos;  // consume flags byte
+
+  if (lacing == 0) {  // no lacing
+    if (pos > stop)
+      return E_FILE_FORMAT_INVALID;
+
+    m_frame_count = 1;
+    m_frames = new (std::nothrow) Frame[m_frame_count];
+    if (m_frames == NULL)
+      return -1;
+
+    Frame& f = m_frames[0];
+    f.pos = pos;
+
+    const long long frame_size = stop - pos;
+
+    if (frame_size > LONG_MAX || frame_size <= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    f.len = static_cast<long>(frame_size);
+
+    return 0;  // success
+  }
+
+  if (pos >= stop)
+    return E_FILE_FORMAT_INVALID;
+
+  unsigned char biased_count;
+
+  status = pReader->Read(pos, 1, &biased_count);
+
+  if (status)
+    return E_FILE_FORMAT_INVALID;
+
+  ++pos;  // consume frame count
+  if (pos > stop)
+    return E_FILE_FORMAT_INVALID;
+
+  m_frame_count = int(biased_count) + 1;
+
+  m_frames = new (std::nothrow) Frame[m_frame_count];
+  if (m_frames == NULL)
+    return -1;
+
+  if (!m_frames)
+    return E_FILE_FORMAT_INVALID;
+
+  if (lacing == 1) {  // Xiph
+    Frame* pf = m_frames;
+    Frame* const pf_end = pf + m_frame_count;
+
+    long long size = 0;
+    int frame_count = m_frame_count;
+
+    while (frame_count > 1) {
+      long frame_size = 0;
+
+      for (;;) {
+        unsigned char val;
+
+        if (pos >= stop)
+          return E_FILE_FORMAT_INVALID;
+
+        status = pReader->Read(pos, 1, &val);
+
+        if (status)
+          return E_FILE_FORMAT_INVALID;
+
+        ++pos;  // consume xiph size byte
+
+        frame_size += val;
+
+        if (val < 255)
+          break;
+      }
+
+      Frame& f = *pf++;
+      assert(pf < pf_end);
+      if (pf >= pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      f.pos = 0;  // patch later
+
+      if (frame_size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      f.len = frame_size;
+      size += frame_size;  // contribution of this frame
+
+      --frame_count;
+    }
+
+    if (pf >= pf_end || pos > stop)
+      return E_FILE_FORMAT_INVALID;
+
+    {
+      Frame& f = *pf++;
+
+      if (pf != pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      f.pos = 0;  // patch later
+
+      const long long total_size = stop - pos;
+
+      if (total_size < size)
+        return E_FILE_FORMAT_INVALID;
+
+      const long long frame_size = total_size - size;
+
+      if (frame_size > LONG_MAX || frame_size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      f.len = static_cast<long>(frame_size);
+    }
+
+    pf = m_frames;
+    while (pf != pf_end) {
+      Frame& f = *pf++;
+      assert((pos + f.len) <= stop);
+
+      if ((pos + f.len) > stop)
+        return E_FILE_FORMAT_INVALID;
+
+      f.pos = pos;
+      pos += f.len;
+    }
+
+    assert(pos == stop);
+    if (pos != stop)
+      return E_FILE_FORMAT_INVALID;
+
+  } else if (lacing == 2) {  // fixed-size lacing
+    if (pos >= stop)
+      return E_FILE_FORMAT_INVALID;
+
+    const long long total_size = stop - pos;
+
+    if ((total_size % m_frame_count) != 0)
+      return E_FILE_FORMAT_INVALID;
+
+    const long long frame_size = total_size / m_frame_count;
+
+    if (frame_size > LONG_MAX || frame_size <= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    Frame* pf = m_frames;
+    Frame* const pf_end = pf + m_frame_count;
+
+    while (pf != pf_end) {
+      assert((pos + frame_size) <= stop);
+      if ((pos + frame_size) > stop)
+        return E_FILE_FORMAT_INVALID;
+
+      Frame& f = *pf++;
+
+      f.pos = pos;
+      f.len = static_cast<long>(frame_size);
+
+      pos += frame_size;
+    }
+
+    assert(pos == stop);
+    if (pos != stop)
+      return E_FILE_FORMAT_INVALID;
+
+  } else {
+    assert(lacing == 3);  // EBML lacing
+
+    if (pos >= stop)
+      return E_FILE_FORMAT_INVALID;
+
+    long long size = 0;
+    int frame_count = m_frame_count;
+
+    long long frame_size = ReadUInt(pReader, pos, len);
+
+    if (frame_size <= 0)
+      return E_FILE_FORMAT_INVALID;
+
+    if (frame_size > LONG_MAX)
+      return E_FILE_FORMAT_INVALID;
+
+    if ((pos + len) > stop)
+      return E_FILE_FORMAT_INVALID;
+
+    pos += len;  // consume length of size of first frame
+
+    if ((pos + frame_size) > stop)
+      return E_FILE_FORMAT_INVALID;
+
+    Frame* pf = m_frames;
+    Frame* const pf_end = pf + m_frame_count;
+
+    {
+      Frame& curr = *pf;
+
+      curr.pos = 0;  // patch later
+
+      curr.len = static_cast<long>(frame_size);
+      size += curr.len;  // contribution of this frame
+    }
+
+    --frame_count;
+
+    while (frame_count > 1) {
+      if (pos >= stop)
+        return E_FILE_FORMAT_INVALID;
+
+      assert(pf < pf_end);
+      if (pf >= pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      const Frame& prev = *pf++;
+      assert(prev.len == frame_size);
+      if (prev.len != frame_size)
+        return E_FILE_FORMAT_INVALID;
+
+      assert(pf < pf_end);
+      if (pf >= pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      Frame& curr = *pf;
+
+      curr.pos = 0;  // patch later
+
+      const long long delta_size_ = ReadUInt(pReader, pos, len);
+
+      if (delta_size_ < 0)
+        return E_FILE_FORMAT_INVALID;
+
+      if ((pos + len) > stop)
+        return E_FILE_FORMAT_INVALID;
+
+      pos += len;  // consume length of (delta) size
+      if (pos > stop)
+        return E_FILE_FORMAT_INVALID;
+
+      const int exp = 7 * len - 1;
+      const long long bias = (1LL << exp) - 1LL;
+      const long long delta_size = delta_size_ - bias;
+
+      frame_size += delta_size;
+
+      if (frame_size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      if (frame_size > LONG_MAX)
+        return E_FILE_FORMAT_INVALID;
+
+      curr.len = static_cast<long>(frame_size);
+      size += curr.len;  // contribution of this frame
+
+      --frame_count;
+    }
+
+    // parse last frame
+    if (frame_count > 0) {
+      if (pos > stop || pf >= pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      const Frame& prev = *pf++;
+      assert(prev.len == frame_size);
+      if (prev.len != frame_size)
+        return E_FILE_FORMAT_INVALID;
+
+      if (pf >= pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      Frame& curr = *pf++;
+      if (pf != pf_end)
+        return E_FILE_FORMAT_INVALID;
+
+      curr.pos = 0;  // patch later
+
+      const long long total_size = stop - pos;
+
+      if (total_size < size)
+        return E_FILE_FORMAT_INVALID;
+
+      frame_size = total_size - size;
+
+      if (frame_size > LONG_MAX || frame_size <= 0)
+        return E_FILE_FORMAT_INVALID;
+
+      curr.len = static_cast<long>(frame_size);
+    }
+
+    pf = m_frames;
+    while (pf != pf_end) {
+      Frame& f = *pf++;
+      assert((pos + f.len) <= stop);
+      if ((pos + f.len) > stop)
+        return E_FILE_FORMAT_INVALID;
+
+      f.pos = pos;
+      pos += f.len;
+    }
+
+    if (pos != stop)
+      return E_FILE_FORMAT_INVALID;
+  }
+
+  return 0;  // success
+}
+
+long long Block::GetTimeCode(const Cluster* pCluster) const {
+  if (pCluster == 0)
+    return m_timecode;
+
+  const long long tc0 = pCluster->GetTimeCode();
+  assert(tc0 >= 0);
+
+  const long long tc = tc0 + m_timecode;
+
+  return tc;  // unscaled timecode units
+}
+
+long long Block::GetTime(const Cluster* pCluster) const {
+  assert(pCluster);
+
+  const long long tc = GetTimeCode(pCluster);
+
+  const Segment* const pSegment = pCluster->m_pSegment;
+  const SegmentInfo* const pInfo = pSegment->GetInfo();
+  assert(pInfo);
+
+  const long long scale = pInfo->GetTimeCodeScale();
+  assert(scale >= 1);
+
+  const long long ns = tc * scale;
+
+  return ns;
+}
+
+long long Block::GetTrackNumber() const { return m_track; }
+
+bool Block::IsKey() const {
+  return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
+}
+
+void Block::SetKey(bool bKey) {
+  if (bKey)
+    m_flags |= static_cast<unsigned char>(1 << 7);
+  else
+    m_flags &= 0x7F;
+}
+
+bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
+
+Block::Lacing Block::GetLacing() const {
+  const int value = int(m_flags & 0x06) >> 1;
+  return static_cast<Lacing>(value);
+}
+
+int Block::GetFrameCount() const { return m_frame_count; }
+
+const Block::Frame& Block::GetFrame(int idx) const {
+  assert(idx >= 0);
+  assert(idx < m_frame_count);
+
+  const Frame& f = m_frames[idx];
+  assert(f.pos > 0);
+  assert(f.len > 0);
+
+  return f;
+}
+
+long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
+  assert(pReader);
+  assert(buf);
+
+  const long status = pReader->Read(pos, len, buf);
+  return status;
+}
+
+long long Block::GetDiscardPadding() const { return m_discard_padding; }
+
+}  // namespace mkvparser
--- /dev/null
+++ b/third_party/libwebm/mkvparser/mkvparser.h
@@ -1,0 +1,1112 @@
+// 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 MKVPARSER_MKVPARSER_H_
+#define MKVPARSER_MKVPARSER_H_
+
+#include <cstddef>
+
+namespace mkvparser {
+
+const int E_PARSE_FAILED = -1;
+const int E_FILE_FORMAT_INVALID = -2;
+const int E_BUFFER_NOT_FULL = -3;
+
+class IMkvReader {
+ public:
+  virtual int Read(long long pos, long len, unsigned char* buf) = 0;
+  virtual int Length(long long* total, long long* available) = 0;
+
+ protected:
+  virtual ~IMkvReader();
+};
+
+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);
+long long UnserializeUInt(IMkvReader*, long long pos, long long size);
+
+long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);
+long UnserializeInt(IMkvReader*, long long pos, long long size,
+                    long long& result);
+
+long UnserializeString(IMkvReader*, long long pos, long long size, char*& str);
+
+long ParseElementHeader(IMkvReader* pReader,
+                        long long& pos,  // consume id and size fields
+                        long long stop,  // if you know size of element's parent
+                        long long& id, long long& size);
+
+bool Match(IMkvReader*, long long&, unsigned long, long long&);
+bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
+
+void GetVersion(int& major, int& minor, int& build, int& revision);
+
+struct EBMLHeader {
+  EBMLHeader();
+  ~EBMLHeader();
+  long long m_version;
+  long long m_readVersion;
+  long long m_maxIdLength;
+  long long m_maxSizeLength;
+  char* m_docType;
+  long long m_docTypeVersion;
+  long long m_docTypeReadVersion;
+
+  long long Parse(IMkvReader*, long long&);
+  void Init();
+};
+
+class Segment;
+class Track;
+class Cluster;
+
+class Block {
+  Block(const Block&);
+  Block& operator=(const Block&);
+
+ public:
+  const long long m_start;
+  const long long m_size;
+
+  Block(long long start, long long size, long long discard_padding);
+  ~Block();
+
+  long Parse(const Cluster*);
+
+  long long GetTrackNumber() const;
+  long long GetTimeCode(const Cluster*) const;  // absolute, but not scaled
+  long long GetTime(const Cluster*) const;  // absolute, and scaled (ns)
+  bool IsKey() const;
+  void SetKey(bool);
+  bool IsInvisible() const;
+
+  enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml };
+  Lacing GetLacing() const;
+
+  int GetFrameCount() const;  // to index frames: [0, count)
+
+  struct Frame {
+    long long pos;  // absolute offset
+    long len;
+
+    long Read(IMkvReader*, unsigned char*) const;
+  };
+
+  const Frame& GetFrame(int frame_index) const;
+
+  long long GetDiscardPadding() const;
+
+ private:
+  long long m_track;  // Track::Number()
+  short m_timecode;  // relative to cluster
+  unsigned char m_flags;
+
+  Frame* m_frames;
+  int m_frame_count;
+
+ protected:
+  const long long m_discard_padding;
+};
+
+class BlockEntry {
+  BlockEntry(const BlockEntry&);
+  BlockEntry& operator=(const BlockEntry&);
+
+ protected:
+  BlockEntry(Cluster*, long index);
+
+ public:
+  virtual ~BlockEntry();
+
+  bool EOS() const { return (GetKind() == kBlockEOS); }
+  const Cluster* GetCluster() const;
+  long GetIndex() const;
+  virtual const Block* GetBlock() const = 0;
+
+  enum Kind { kBlockEOS, kBlockSimple, kBlockGroup };
+  virtual Kind GetKind() const = 0;
+
+ protected:
+  Cluster* const m_pCluster;
+  const long m_index;
+};
+
+class SimpleBlock : public BlockEntry {
+  SimpleBlock(const SimpleBlock&);
+  SimpleBlock& operator=(const SimpleBlock&);
+
+ public:
+  SimpleBlock(Cluster*, long index, long long start, long long size);
+  long Parse();
+
+  Kind GetKind() const;
+  const Block* GetBlock() const;
+
+ protected:
+  Block m_block;
+};
+
+class BlockGroup : public BlockEntry {
+  BlockGroup(const BlockGroup&);
+  BlockGroup& operator=(const BlockGroup&);
+
+ public:
+  BlockGroup(Cluster*, long index,
+             long long block_start,  // absolute pos of block's payload
+             long long block_size,  // size of block's payload
+             long long prev, long long next, long long duration,
+             long long discard_padding);
+
+  long Parse();
+
+  Kind GetKind() const;
+  const Block* GetBlock() const;
+
+  long long GetPrevTimeCode() const;  // relative to block's time
+  long long GetNextTimeCode() const;  // as above
+  long long GetDurationTimeCode() const;
+
+ private:
+  Block m_block;
+  const long long m_prev;
+  const long long m_next;
+  const long long m_duration;
+};
+
+///////////////////////////////////////////////////////////////
+// ContentEncoding element
+// Elements used to describe if the track data has been encrypted or
+// compressed with zlib or header stripping.
+class ContentEncoding {
+ public:
+  enum { kCTR = 1 };
+
+  ContentEncoding();
+  ~ContentEncoding();
+
+  // ContentCompression element names
+  struct ContentCompression {
+    ContentCompression();
+    ~ContentCompression();
+
+    unsigned long long algo;
+    unsigned char* settings;
+    long long settings_len;
+  };
+
+  // ContentEncAESSettings element names
+  struct ContentEncAESSettings {
+    ContentEncAESSettings() : cipher_mode(kCTR) {}
+    ~ContentEncAESSettings() {}
+
+    unsigned long long cipher_mode;
+  };
+
+  // ContentEncryption element names
+  struct ContentEncryption {
+    ContentEncryption();
+    ~ContentEncryption();
+
+    unsigned long long algo;
+    unsigned char* key_id;
+    long long key_id_len;
+    unsigned char* signature;
+    long long signature_len;
+    unsigned char* sig_key_id;
+    long long sig_key_id_len;
+    unsigned long long sig_algo;
+    unsigned long long sig_hash_algo;
+
+    ContentEncAESSettings aes_settings;
+  };
+
+  // Returns ContentCompression represented by |idx|. Returns NULL if |idx|
+  // is out of bounds.
+  const ContentCompression* GetCompressionByIndex(unsigned long idx) const;
+
+  // Returns number of ContentCompression elements in this ContentEncoding
+  // element.
+  unsigned long GetCompressionCount() const;
+
+  // Parses the ContentCompression element from |pReader|. |start| is the
+  // starting offset of the ContentCompression payload. |size| is the size in
+  // bytes of the ContentCompression payload. |compression| is where the parsed
+  // values will be stored.
+  long ParseCompressionEntry(long long start, long long size,
+                             IMkvReader* pReader,
+                             ContentCompression* compression);
+
+  // Returns ContentEncryption represented by |idx|. Returns NULL if |idx|
+  // is out of bounds.
+  const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const;
+
+  // Returns number of ContentEncryption elements in this ContentEncoding
+  // element.
+  unsigned long GetEncryptionCount() const;
+
+  // Parses the ContentEncAESSettings element from |pReader|. |start| is the
+  // starting offset of the ContentEncAESSettings payload. |size| is the
+  // size in bytes of the ContentEncAESSettings payload. |encryption| is
+  // where the parsed values will be stored.
+  long ParseContentEncAESSettingsEntry(long long start, long long size,
+                                       IMkvReader* pReader,
+                                       ContentEncAESSettings* aes);
+
+  // Parses the ContentEncoding element from |pReader|. |start| is the
+  // starting offset of the ContentEncoding payload. |size| is the size in
+  // bytes of the ContentEncoding payload. Returns true on success.
+  long ParseContentEncodingEntry(long long start, long long size,
+                                 IMkvReader* pReader);
+
+  // Parses the ContentEncryption element from |pReader|. |start| is the
+  // starting offset of the ContentEncryption payload. |size| is the size in
+  // bytes of the ContentEncryption payload. |encryption| is where the parsed
+  // values will be stored.
+  long ParseEncryptionEntry(long long start, long long size,
+                            IMkvReader* pReader, ContentEncryption* encryption);
+
+  unsigned long long encoding_order() const { return encoding_order_; }
+  unsigned long long encoding_scope() const { return encoding_scope_; }
+  unsigned long long encoding_type() const { return encoding_type_; }
+
+ private:
+  // Member variables for list of ContentCompression elements.
+  ContentCompression** compression_entries_;
+  ContentCompression** compression_entries_end_;
+
+  // Member variables for list of ContentEncryption elements.
+  ContentEncryption** encryption_entries_;
+  ContentEncryption** encryption_entries_end_;
+
+  // ContentEncoding element names
+  unsigned long long encoding_order_;
+  unsigned long long encoding_scope_;
+  unsigned long long encoding_type_;
+
+  // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
+  ContentEncoding(const ContentEncoding&);
+  ContentEncoding& operator=(const ContentEncoding&);
+};
+
+class Track {
+  Track(const Track&);
+  Track& operator=(const Track&);
+
+ public:
+  class Info;
+  static long Create(Segment*, const Info&, long long element_start,
+                     long long element_size, Track*&);
+
+  enum Type { kVideo = 1, kAudio = 2, kSubtitle = 0x11, kMetadata = 0x21 };
+
+  Segment* const m_pSegment;
+  const long long m_element_start;
+  const long long m_element_size;
+  virtual ~Track();
+
+  long GetType() const;
+  long GetNumber() const;
+  unsigned long long GetUid() const;
+  const char* GetNameAsUTF8() const;
+  const char* GetLanguage() const;
+  const char* GetCodecNameAsUTF8() const;
+  const char* GetCodecId() const;
+  const unsigned char* GetCodecPrivate(size_t&) const;
+  bool GetLacing() const;
+  unsigned long long GetDefaultDuration() const;
+  unsigned long long GetCodecDelay() const;
+  unsigned long long GetSeekPreRoll() const;
+
+  const BlockEntry* GetEOS() const;
+
+  struct Settings {
+    long long start;
+    long long size;
+  };
+
+  class Info {
+   public:
+    Info();
+    ~Info();
+    int Copy(Info&) const;
+    void Clear();
+    long type;
+    long number;
+    unsigned long long uid;
+    unsigned long long defaultDuration;
+    unsigned long long codecDelay;
+    unsigned long long seekPreRoll;
+    char* nameAsUTF8;
+    char* language;
+    char* codecId;
+    char* codecNameAsUTF8;
+    unsigned char* codecPrivate;
+    size_t codecPrivateSize;
+    bool lacing;
+    Settings settings;
+
+   private:
+    Info(const Info&);
+    Info& operator=(const Info&);
+    int CopyStr(char* Info::*str, Info&) const;
+  };
+
+  long GetFirst(const BlockEntry*&) const;
+  long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
+  virtual bool VetEntry(const BlockEntry*) const;
+  virtual long Seek(long long time_ns, const BlockEntry*&) const;
+
+  const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
+  unsigned long GetContentEncodingCount() const;
+
+  long ParseContentEncodingsEntry(long long start, long long size);
+
+ protected:
+  Track(Segment*, long long element_start, long long element_size);
+
+  Info m_info;
+
+  class EOSBlock : public BlockEntry {
+   public:
+    EOSBlock();
+
+    Kind GetKind() const;
+    const Block* GetBlock() const;
+  };
+
+  EOSBlock m_eos;
+
+ private:
+  ContentEncoding** content_encoding_entries_;
+  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&);
+
+  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*&);
+
+  long long GetWidth() const;
+  long long GetHeight() const;
+  long long GetDisplayWidth() const;
+  long long GetDisplayHeight() const;
+  long long GetDisplayUnit() const;
+  long long GetStereoMode() const;
+  double GetFrameRate() const;
+
+  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;
+  long long m_display_width;
+  long long m_display_height;
+  long long m_display_unit;
+  long long m_stereo_mode;
+
+  double m_rate;
+
+  Colour* m_colour;
+};
+
+class AudioTrack : public Track {
+  AudioTrack(const AudioTrack&);
+  AudioTrack& operator=(const AudioTrack&);
+
+  AudioTrack(Segment*, long long element_start, long long element_size);
+
+ public:
+  static long Parse(Segment*, const Info&, long long element_start,
+                    long long element_size, AudioTrack*&);
+
+  double GetSamplingRate() const;
+  long long GetChannels() const;
+  long long GetBitDepth() const;
+
+ private:
+  double m_rate;
+  long long m_channels;
+  long long m_bitDepth;
+};
+
+class Tracks {
+  Tracks(const Tracks&);
+  Tracks& operator=(const Tracks&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  Tracks(Segment*, long long start, long long size, long long element_start,
+         long long element_size);
+
+  ~Tracks();
+
+  long Parse();
+
+  unsigned long GetTracksCount() const;
+
+  const Track* GetTrackByNumber(long tn) const;
+  const Track* GetTrackByIndex(unsigned long idx) const;
+
+ private:
+  Track** m_trackEntries;
+  Track** m_trackEntriesEnd;
+
+  long ParseTrackEntry(long long payload_start, long long payload_size,
+                       long long element_start, long long element_size,
+                       Track*&) const;
+};
+
+class Chapters {
+  Chapters(const Chapters&);
+  Chapters& operator=(const Chapters&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  Chapters(Segment*, long long payload_start, long long payload_size,
+           long long element_start, long long element_size);
+
+  ~Chapters();
+
+  long Parse();
+
+  class Atom;
+  class Edition;
+
+  class Display {
+    friend class Atom;
+    Display();
+    Display(const Display&);
+    ~Display();
+    Display& operator=(const Display&);
+
+   public:
+    const char* GetString() const;
+    const char* GetLanguage() const;
+    const char* GetCountry() const;
+
+   private:
+    void Init();
+    void ShallowCopy(Display&) const;
+    void Clear();
+    long Parse(IMkvReader*, long long pos, long long size);
+
+    char* m_string;
+    char* m_language;
+    char* m_country;
+  };
+
+  class Atom {
+    friend class Edition;
+    Atom();
+    Atom(const Atom&);
+    ~Atom();
+    Atom& operator=(const Atom&);
+
+   public:
+    unsigned long long GetUID() const;
+    const char* GetStringUID() const;
+
+    long long GetStartTimecode() const;
+    long long GetStopTimecode() const;
+
+    long long GetStartTime(const Chapters*) const;
+    long long GetStopTime(const Chapters*) const;
+
+    int GetDisplayCount() const;
+    const Display* GetDisplay(int index) const;
+
+   private:
+    void Init();
+    void ShallowCopy(Atom&) const;
+    void Clear();
+    long Parse(IMkvReader*, long long pos, long long size);
+    static long long GetTime(const Chapters*, long long timecode);
+
+    long ParseDisplay(IMkvReader*, long long pos, long long size);
+    bool ExpandDisplaysArray();
+
+    char* m_string_uid;
+    unsigned long long m_uid;
+    long long m_start_timecode;
+    long long m_stop_timecode;
+
+    Display* m_displays;
+    int m_displays_size;
+    int m_displays_count;
+  };
+
+  class Edition {
+    friend class Chapters;
+    Edition();
+    Edition(const Edition&);
+    ~Edition();
+    Edition& operator=(const Edition&);
+
+   public:
+    int GetAtomCount() const;
+    const Atom* GetAtom(int index) const;
+
+   private:
+    void Init();
+    void ShallowCopy(Edition&) const;
+    void Clear();
+    long Parse(IMkvReader*, long long pos, long long size);
+
+    long ParseAtom(IMkvReader*, long long pos, long long size);
+    bool ExpandAtomsArray();
+
+    Atom* m_atoms;
+    int m_atoms_size;
+    int m_atoms_count;
+  };
+
+  int GetEditionCount() const;
+  const Edition* GetEdition(int index) const;
+
+ private:
+  long ParseEdition(long long pos, long long size);
+  bool ExpandEditionsArray();
+
+  Edition* m_editions;
+  int m_editions_size;
+  int m_editions_count;
+};
+
+class Tags {
+  Tags(const Tags&);
+  Tags& operator=(const Tags&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  Tags(Segment*, long long payload_start, long long payload_size,
+       long long element_start, long long element_size);
+
+  ~Tags();
+
+  long Parse();
+
+  class Tag;
+  class SimpleTag;
+
+  class SimpleTag {
+    friend class Tag;
+    SimpleTag();
+    SimpleTag(const SimpleTag&);
+    ~SimpleTag();
+    SimpleTag& operator=(const SimpleTag&);
+
+   public:
+    const char* GetTagName() const;
+    const char* GetTagString() const;
+
+   private:
+    void Init();
+    void ShallowCopy(SimpleTag&) const;
+    void Clear();
+    long Parse(IMkvReader*, long long pos, long long size);
+
+    char* m_tag_name;
+    char* m_tag_string;
+  };
+
+  class Tag {
+    friend class Tags;
+    Tag();
+    Tag(const Tag&);
+    ~Tag();
+    Tag& operator=(const Tag&);
+
+   public:
+    int GetSimpleTagCount() const;
+    const SimpleTag* GetSimpleTag(int index) const;
+
+   private:
+    void Init();
+    void ShallowCopy(Tag&) const;
+    void Clear();
+    long Parse(IMkvReader*, long long pos, long long size);
+
+    long ParseSimpleTag(IMkvReader*, long long pos, long long size);
+    bool ExpandSimpleTagsArray();
+
+    SimpleTag* m_simple_tags;
+    int m_simple_tags_size;
+    int m_simple_tags_count;
+  };
+
+  int GetTagCount() const;
+  const Tag* GetTag(int index) const;
+
+ private:
+  long ParseTag(long long pos, long long size);
+  bool ExpandTagsArray();
+
+  Tag* m_tags;
+  int m_tags_size;
+  int m_tags_count;
+};
+
+class SegmentInfo {
+  SegmentInfo(const SegmentInfo&);
+  SegmentInfo& operator=(const SegmentInfo&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  SegmentInfo(Segment*, long long start, long long size,
+              long long element_start, long long element_size);
+
+  ~SegmentInfo();
+
+  long Parse();
+
+  long long GetTimeCodeScale() const;
+  long long GetDuration() const;  // scaled
+  const char* GetMuxingAppAsUTF8() const;
+  const char* GetWritingAppAsUTF8() const;
+  const char* GetTitleAsUTF8() const;
+
+ private:
+  long long m_timecodeScale;
+  double m_duration;
+  char* m_pMuxingAppAsUTF8;
+  char* m_pWritingAppAsUTF8;
+  char* m_pTitleAsUTF8;
+};
+
+class SeekHead {
+  SeekHead(const SeekHead&);
+  SeekHead& operator=(const SeekHead&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  SeekHead(Segment*, long long start, long long size, long long element_start,
+           long long element_size);
+
+  ~SeekHead();
+
+  long Parse();
+
+  struct Entry {
+    // the SeekHead entry payload
+    long long id;
+    long long pos;
+
+    // absolute pos of SeekEntry ID
+    long long element_start;
+
+    // SeekEntry ID size + size size + payload
+    long long element_size;
+  };
+
+  int GetCount() const;
+  const Entry* GetEntry(int idx) const;
+
+  struct VoidElement {
+    // absolute pos of Void ID
+    long long element_start;
+
+    // ID size + size size + payload size
+    long long element_size;
+  };
+
+  int GetVoidElementCount() const;
+  const VoidElement* GetVoidElement(int idx) const;
+
+ private:
+  Entry* m_entries;
+  int m_entry_count;
+
+  VoidElement* m_void_elements;
+  int m_void_element_count;
+
+  static bool ParseEntry(IMkvReader*,
+                         long long pos,  // payload
+                         long long size, Entry*);
+};
+
+class Cues;
+class CuePoint {
+  friend class Cues;
+
+  CuePoint(long, long long);
+  ~CuePoint();
+
+  CuePoint(const CuePoint&);
+  CuePoint& operator=(const CuePoint&);
+
+ public:
+  long long m_element_start;
+  long long m_element_size;
+
+  bool Load(IMkvReader*);
+
+  long long GetTimeCode() const;  // absolute but unscaled
+  long long GetTime(const Segment*) const;  // absolute and scaled (ns units)
+
+  struct TrackPosition {
+    long long m_track;
+    long long m_pos;  // of cluster
+    long long m_block;
+    // codec_state  //defaults to 0
+    // reference = clusters containing req'd referenced blocks
+    //  reftime = timecode of the referenced block
+
+    bool Parse(IMkvReader*, long long, long long);
+  };
+
+  const TrackPosition* Find(const Track*) const;
+
+ private:
+  const long m_index;
+  long long m_timecode;
+  TrackPosition* m_track_positions;
+  size_t m_track_positions_count;
+};
+
+class Cues {
+  friend class Segment;
+
+  Cues(Segment*, long long start, long long size, long long element_start,
+       long long element_size);
+  ~Cues();
+
+  Cues(const Cues&);
+  Cues& operator=(const Cues&);
+
+ public:
+  Segment* const m_pSegment;
+  const long long m_start;
+  const long long m_size;
+  const long long m_element_start;
+  const long long m_element_size;
+
+  bool Find(  // lower bound of time_ns
+      long long time_ns, const Track*, const CuePoint*&,
+      const CuePoint::TrackPosition*&) const;
+
+  const CuePoint* GetFirst() const;
+  const CuePoint* GetLast() const;
+  const CuePoint* GetNext(const CuePoint*) const;
+
+  const BlockEntry* GetBlock(const CuePoint*,
+                             const CuePoint::TrackPosition*) const;
+
+  bool LoadCuePoint() const;
+  long GetCount() const;  // loaded only
+  // long GetTotal() const;  //loaded + preloaded
+  bool DoneParsing() const;
+
+ private:
+  bool Init() const;
+  bool PreloadCuePoint(long&, long long) const;
+
+  mutable CuePoint** m_cue_points;
+  mutable long m_count;
+  mutable long m_preload_count;
+  mutable long long m_pos;
+};
+
+class Cluster {
+  friend class Segment;
+
+  Cluster(const Cluster&);
+  Cluster& operator=(const Cluster&);
+
+ public:
+  Segment* const m_pSegment;
+
+ public:
+  static Cluster* Create(Segment*,
+                         long index,  // index in segment
+                         long long off);  // offset relative to segment
+  // long long element_size);
+
+  Cluster();  // EndOfStream
+  ~Cluster();
+
+  bool EOS() const;
+
+  long long GetTimeCode() const;  // absolute, but not scaled
+  long long GetTime() const;  // absolute, and scaled (nanosecond units)
+  long long GetFirstTime() const;  // time (ns) of first (earliest) block
+  long long GetLastTime() const;  // time (ns) of last (latest) block
+
+  long GetFirst(const BlockEntry*&) const;
+  long GetLast(const BlockEntry*&) const;
+  long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
+
+  const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
+  const BlockEntry* GetEntry(const CuePoint&,
+                             const CuePoint::TrackPosition&) const;
+  // const BlockEntry* GetMaxKey(const VideoTrack*) const;
+
+  //    static bool HasBlockEntries(const Segment*, long long);
+
+  static long HasBlockEntries(const Segment*, long long idoff, long long& pos,
+                              long& size);
+
+  long GetEntryCount() const;
+
+  long Load(long long& pos, long& size) const;
+
+  long Parse(long long& pos, long& size) const;
+  long GetEntry(long index, const mkvparser::BlockEntry*&) const;
+
+ protected:
+  Cluster(Segment*, long index, long long element_start);
+  // long long element_size);
+
+ public:
+  const long long m_element_start;
+  long long GetPosition() const;  // offset relative to segment
+
+  long GetIndex() const;
+  long long GetElementSize() const;
+  // long long GetPayloadSize() const;
+
+  // long long Unparsed() const;
+
+ private:
+  long m_index;
+  mutable long long m_pos;
+  // mutable long long m_size;
+  mutable long long m_element_size;
+  mutable long long m_timecode;
+  mutable BlockEntry** m_entries;
+  mutable long m_entries_size;
+  mutable long m_entries_count;
+
+  long ParseSimpleBlock(long long, long long&, long&);
+  long ParseBlockGroup(long long, long long&, long&);
+
+  long CreateBlock(long long id, long long pos, long long size,
+                   long long discard_padding);
+  long CreateBlockGroup(long long start_offset, long long size,
+                        long long discard_padding);
+  long CreateSimpleBlock(long long, long long);
+};
+
+class Segment {
+  friend class Cues;
+  friend class Track;
+  friend class VideoTrack;
+
+  Segment(const Segment&);
+  Segment& operator=(const Segment&);
+
+ private:
+  Segment(IMkvReader*, long long elem_start,
+          // long long elem_size,
+          long long pos, long long size);
+
+ public:
+  IMkvReader* const m_pReader;
+  const long long m_element_start;
+  // const long long m_element_size;
+  const long long m_start;  // posn of segment payload
+  const long long m_size;  // size of segment payload
+  Cluster m_eos;  // TODO: make private?
+
+  static long long CreateInstance(IMkvReader*, long long, Segment*&);
+  ~Segment();
+
+  long Load();  // loads headers and all clusters
+
+  // for incremental loading
+  // long long Unparsed() const;
+  bool DoneParsing() const;
+  long long ParseHeaders();  // stops when first cluster is found
+  // long FindNextCluster(long long& pos, long& size) const;
+  long LoadCluster(long long& pos, long& size);  // load one cluster
+  long LoadCluster();
+
+  long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos,
+                 long& size);
+
+  const SeekHead* GetSeekHead() const;
+  const Tracks* GetTracks() const;
+  const SegmentInfo* GetInfo() const;
+  const Cues* GetCues() const;
+  const Chapters* GetChapters() const;
+  const Tags* GetTags() const;
+
+  long long GetDuration() const;
+
+  unsigned long GetCount() const;
+  const Cluster* GetFirst() const;
+  const Cluster* GetLast() const;
+  const Cluster* GetNext(const Cluster*);
+
+  const Cluster* FindCluster(long long time_nanoseconds) const;
+  // const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
+
+  const Cluster* FindOrPreloadCluster(long long pos);
+
+  long ParseCues(long long cues_off,  // offset relative to start of segment
+                 long long& parse_pos, long& parse_len);
+
+ private:
+  long long m_pos;  // absolute file posn; what has been consumed so far
+  Cluster* m_pUnknownSize;
+
+  SeekHead* m_pSeekHead;
+  SegmentInfo* m_pInfo;
+  Tracks* m_pTracks;
+  Cues* m_pCues;
+  Chapters* m_pChapters;
+  Tags* m_pTags;
+  Cluster** m_clusters;
+  long m_clusterCount;  // number of entries for which m_index >= 0
+  long m_clusterPreloadCount;  // number of entries for which m_index < 0
+  long m_clusterSize;  // array size
+
+  long DoLoadCluster(long long&, long&);
+  long DoLoadClusterUnknownSize(long long&, long&);
+  long DoParseNext(const Cluster*&, long long&, long&);
+
+  bool AppendCluster(Cluster*);
+  bool PreloadCluster(Cluster*, ptrdiff_t);
+
+  // void ParseSeekHead(long long pos, long long size);
+  // void ParseSeekEntry(long long pos, long long size);
+  // void ParseCues(long long);
+
+  const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&);
+};
+
+}  // namespace mkvparser
+
+inline long mkvparser::Segment::LoadCluster() {
+  long long pos;
+  long size;
+
+  return LoadCluster(pos, size);
+}
+
+#endif  // MKVPARSER_MKVPARSER_H_
--- /dev/null
+++ b/third_party/libwebm/mkvparser/mkvreader.cc
@@ -1,0 +1,131 @@
+// Copyright (c) 2010 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 "mkvparser/mkvreader.h"
+
+#include <cassert>
+
+namespace mkvparser {
+
+MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {}
+
+MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) {
+  GetFileSize();
+}
+
+MkvReader::~MkvReader() {
+  if (reader_owns_file_)
+    Close();
+  m_file = NULL;
+}
+
+int MkvReader::Open(const char* fileName) {
+  if (fileName == NULL)
+    return -1;
+
+  if (m_file)
+    return -1;
+
+#ifdef _MSC_VER
+  const errno_t e = fopen_s(&m_file, fileName, "rb");
+
+  if (e)
+    return -1;  // error
+#else
+  m_file = fopen(fileName, "rb");
+
+  if (m_file == NULL)
+    return -1;
+#endif
+  return !GetFileSize();
+}
+
+bool MkvReader::GetFileSize() {
+  if (m_file == NULL)
+    return false;
+#ifdef _MSC_VER
+  int status = _fseeki64(m_file, 0L, SEEK_END);
+
+  if (status)
+    return false;  // error
+
+  m_length = _ftelli64(m_file);
+#else
+  fseek(m_file, 0L, SEEK_END);
+  m_length = ftell(m_file);
+#endif
+  assert(m_length >= 0);
+
+  if (m_length < 0)
+    return false;
+
+#ifdef _MSC_VER
+  status = _fseeki64(m_file, 0L, SEEK_SET);
+
+  if (status)
+    return false;  // error
+#else
+  fseek(m_file, 0L, SEEK_SET);
+#endif
+
+  return true;
+}
+
+void MkvReader::Close() {
+  if (m_file != NULL) {
+    fclose(m_file);
+    m_file = NULL;
+  }
+}
+
+int MkvReader::Length(long long* total, long long* available) {
+  if (m_file == NULL)
+    return -1;
+
+  if (total)
+    *total = m_length;
+
+  if (available)
+    *available = m_length;
+
+  return 0;
+}
+
+int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
+  if (m_file == NULL)
+    return -1;
+
+  if (offset < 0)
+    return -1;
+
+  if (len < 0)
+    return -1;
+
+  if (len == 0)
+    return 0;
+
+  if (offset >= m_length)
+    return -1;
+
+#ifdef _MSC_VER
+  const int status = _fseeki64(m_file, offset, SEEK_SET);
+
+  if (status)
+    return -1;  // error
+#else
+  fseek(m_file, offset, SEEK_SET);
+#endif
+
+  const size_t size = fread(buffer, 1, len, m_file);
+
+  if (size < size_t(len))
+    return -1;  // error
+
+  return 0;  // success
+}
+
+}  // namespace mkvparser
\ No newline at end of file
--- /dev/null
+++ b/third_party/libwebm/mkvparser/mkvreader.h
@@ -1,0 +1,45 @@
+// Copyright (c) 2010 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 MKVPARSER_MKVREADER_H_
+#define MKVPARSER_MKVREADER_H_
+
+#include <cstdio>
+
+#include "mkvparser/mkvparser.h"
+
+namespace mkvparser {
+
+class MkvReader : public IMkvReader {
+ public:
+  MkvReader();
+  explicit MkvReader(FILE* fp);
+  virtual ~MkvReader();
+
+  int Open(const char*);
+  void Close();
+
+  virtual int Read(long long position, long length, unsigned char* buffer);
+  virtual int Length(long long* total, long long* available);
+
+ private:
+  MkvReader(const MkvReader&);
+  MkvReader& operator=(const MkvReader&);
+
+  // Determines the size of the file. This is called either by the constructor
+  // or by the Open function depending on file ownership. Returns true on
+  // success.
+  bool GetFileSize();
+
+  long long m_length;
+  FILE* m_file;
+  bool reader_owns_file_;
+};
+
+}  // namespace mkvparser
+
+#endif  // MKVPARSER_MKVREADER_H_
--- a/third_party/libwebm/mkvreader.cpp
+++ /dev/null
@@ -1,132 +1,0 @@
-// Copyright (c) 2010 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 "mkvreader.hpp"
-
-#include <cassert>
-
-namespace mkvparser {
-
-MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {}
-
-MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) {
-  GetFileSize();
-}
-
-MkvReader::~MkvReader() {
-  if (reader_owns_file_)
-    Close();
-  m_file = NULL;
-}
-
-int MkvReader::Open(const char* fileName) {
-  if (fileName == NULL)
-    return -1;
-
-  if (m_file)
-    return -1;
-
-#ifdef _MSC_VER
-  const errno_t e = fopen_s(&m_file, fileName, "rb");
-
-  if (e)
-    return -1;  // error
-#else
-  m_file = fopen(fileName, "rb");
-
-  if (m_file == NULL)
-    return -1;
-#endif
-  return !GetFileSize();
-}
-
-bool MkvReader::GetFileSize() {
-  if (m_file == NULL)
-    return false;
-#ifdef _MSC_VER
-  int status = _fseeki64(m_file, 0L, SEEK_END);
-
-  if (status)
-    return false;  // error
-
-  m_length = _ftelli64(m_file);
-#else
-  fseek(m_file, 0L, SEEK_END);
-  m_length = ftell(m_file);
-#endif
-  assert(m_length >= 0);
-
-  if (m_length < 0)
-    return false;
-
-#ifdef _MSC_VER
-  status = _fseeki64(m_file, 0L, SEEK_SET);
-
-  if (status)
-    return false;  // error
-#else
-  fseek(m_file, 0L, SEEK_SET);
-#endif
-
-  return true;
-}
-
-void MkvReader::Close() {
-  if (m_file != NULL) {
-    fclose(m_file);
-    m_file = NULL;
-  }
-}
-
-int MkvReader::Length(long long* total, long long* available) {
-  if (m_file == NULL)
-    return -1;
-
-  if (total)
-    *total = m_length;
-
-  if (available)
-    *available = m_length;
-
-  return 0;
-}
-
-int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
-  if (m_file == NULL)
-    return -1;
-
-  if (offset < 0)
-    return -1;
-
-  if (len < 0)
-    return -1;
-
-  if (len == 0)
-    return 0;
-
-  if (offset >= m_length)
-    return -1;
-
-#ifdef _MSC_VER
-  const int status = _fseeki64(m_file, offset, SEEK_SET);
-
-  if (status)
-    return -1;  // error
-#else
-  fseek(m_file, offset, SEEK_SET);
-#endif
-
-  const size_t size = fread(buffer, 1, len, m_file);
-
-  if (size < size_t(len))
-    return -1;  // error
-
-  return 0;  // success
-}
-
-}  // end namespace mkvparser
--- a/third_party/libwebm/mkvreader.hpp
+++ /dev/null
@@ -1,45 +1,0 @@
-// Copyright (c) 2010 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 MKVREADER_HPP
-#define MKVREADER_HPP
-
-#include "mkvparser.hpp"
-#include <cstdio>
-
-namespace mkvparser {
-
-class MkvReader : public IMkvReader {
- public:
-  MkvReader();
-  explicit MkvReader(FILE* fp);
-  virtual ~MkvReader();
-
-  int Open(const char*);
-  void Close();
-
-  virtual int Read(long long position, long length, unsigned char* buffer);
-  virtual int Length(long long* total, long long* available);
-
- private:
-  MkvReader(const MkvReader&);
-  MkvReader& operator=(const MkvReader&);
-
-  // Determines the size of the file. This is called either by the constructor
-  // or by the Open function depending on file ownership. Returns true on
-  // success.
-  bool GetFileSize();
-
-  long long m_length;
-  FILE* m_file;
-  bool reader_owns_file_;
-};
-
-}  // end namespace mkvparser
-
-#endif  // MKVREADER_HPP
--- a/third_party/libwebm/mkvwriter.cpp
+++ /dev/null
@@ -1,90 +1,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 "mkvwriter.hpp"
-
-#ifdef _MSC_VER
-#include <share.h>  // for _SH_DENYWR
-#endif
-
-#include <new>
-
-namespace mkvmuxer {
-
-MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}
-
-MkvWriter::MkvWriter(FILE* fp) : file_(fp), writer_owns_file_(false) {}
-
-MkvWriter::~MkvWriter() { Close(); }
-
-int32 MkvWriter::Write(const void* buffer, uint32 length) {
-  if (!file_)
-    return -1;
-
-  if (length == 0)
-    return 0;
-
-  if (buffer == NULL)
-    return -1;
-
-  const size_t bytes_written = fwrite(buffer, 1, length, file_);
-
-  return (bytes_written == length) ? 0 : -1;
-}
-
-bool MkvWriter::Open(const char* filename) {
-  if (filename == NULL)
-    return false;
-
-  if (file_)
-    return false;
-
-#ifdef _MSC_VER
-  file_ = _fsopen(filename, "wb", _SH_DENYWR);
-#else
-  file_ = fopen(filename, "wb");
-#endif
-  if (file_ == NULL)
-    return false;
-  return true;
-}
-
-void MkvWriter::Close() {
-  if (file_ && writer_owns_file_) {
-    fclose(file_);
-  }
-  file_ = NULL;
-}
-
-int64 MkvWriter::Position() const {
-  if (!file_)
-    return 0;
-
-#ifdef _MSC_VER
-  return _ftelli64(file_);
-#else
-  return ftell(file_);
-#endif
-}
-
-int32 MkvWriter::Position(int64 position) {
-  if (!file_)
-    return -1;
-
-#ifdef _MSC_VER
-  return _fseeki64(file_, position, SEEK_SET);
-#else
-  return fseek(file_, position, SEEK_SET);
-#endif
-}
-
-bool MkvWriter::Seekable() const { return true; }
-
-void MkvWriter::ElementStartNotify(uint64, int64) {}
-
-}  // namespace mkvmuxer
--- a/third_party/libwebm/mkvwriter.hpp
+++ /dev/null
@@ -1,51 +1,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 MKVWRITER_HPP
-#define MKVWRITER_HPP
-
-#include <stdio.h>
-
-#include "mkvmuxer.hpp"
-#include "mkvmuxertypes.hpp"
-
-namespace mkvmuxer {
-
-// Default implementation of the IMkvWriter interface on Windows.
-class MkvWriter : public IMkvWriter {
- public:
-  MkvWriter();
-  explicit MkvWriter(FILE* fp);
-  virtual ~MkvWriter();
-
-  // IMkvWriter interface
-  virtual int64 Position() const;
-  virtual int32 Position(int64 position);
-  virtual bool Seekable() const;
-  virtual int32 Write(const void* buffer, uint32 length);
-  virtual void ElementStartNotify(uint64 element_id, int64 position);
-
-  // Creates and opens a file for writing. |filename| is the name of the file
-  // to open. This function will overwrite the contents of |filename|. Returns
-  // true on success.
-  bool Open(const char* filename);
-
-  // Closes an opened file.
-  void Close();
-
- private:
-  // File handle to output file.
-  FILE* file_;
-  bool writer_owns_file_;
-
-  LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
-};
-
-}  // end namespace mkvmuxer
-
-#endif  // MKVWRITER_HPP
--- a/third_party/libwebm/webmids.hpp
+++ /dev/null
@@ -1,155 +1,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 WEBMIDS_HPP
-#define WEBMIDS_HPP
-
-namespace mkvmuxer {
-
-enum MkvId {
-  kMkvEBML = 0x1A45DFA3,
-  kMkvEBMLVersion = 0x4286,
-  kMkvEBMLReadVersion = 0x42F7,
-  kMkvEBMLMaxIDLength = 0x42F2,
-  kMkvEBMLMaxSizeLength = 0x42F3,
-  kMkvDocType = 0x4282,
-  kMkvDocTypeVersion = 0x4287,
-  kMkvDocTypeReadVersion = 0x4285,
-  kMkvVoid = 0xEC,
-  kMkvSignatureSlot = 0x1B538667,
-  kMkvSignatureAlgo = 0x7E8A,
-  kMkvSignatureHash = 0x7E9A,
-  kMkvSignaturePublicKey = 0x7EA5,
-  kMkvSignature = 0x7EB5,
-  kMkvSignatureElements = 0x7E5B,
-  kMkvSignatureElementList = 0x7E7B,
-  kMkvSignedElement = 0x6532,
-  // segment
-  kMkvSegment = 0x18538067,
-  // Meta Seek Information
-  kMkvSeekHead = 0x114D9B74,
-  kMkvSeek = 0x4DBB,
-  kMkvSeekID = 0x53AB,
-  kMkvSeekPosition = 0x53AC,
-  // Segment Information
-  kMkvInfo = 0x1549A966,
-  kMkvTimecodeScale = 0x2AD7B1,
-  kMkvDuration = 0x4489,
-  kMkvDateUTC = 0x4461,
-  kMkvTitle = 0x7BA9,
-  kMkvMuxingApp = 0x4D80,
-  kMkvWritingApp = 0x5741,
-  // Cluster
-  kMkvCluster = 0x1F43B675,
-  kMkvTimecode = 0xE7,
-  kMkvPrevSize = 0xAB,
-  kMkvBlockGroup = 0xA0,
-  kMkvBlock = 0xA1,
-  kMkvBlockDuration = 0x9B,
-  kMkvReferenceBlock = 0xFB,
-  kMkvLaceNumber = 0xCC,
-  kMkvSimpleBlock = 0xA3,
-  kMkvBlockAdditions = 0x75A1,
-  kMkvBlockMore = 0xA6,
-  kMkvBlockAddID = 0xEE,
-  kMkvBlockAdditional = 0xA5,
-  kMkvDiscardPadding = 0x75A2,
-  // Track
-  kMkvTracks = 0x1654AE6B,
-  kMkvTrackEntry = 0xAE,
-  kMkvTrackNumber = 0xD7,
-  kMkvTrackUID = 0x73C5,
-  kMkvTrackType = 0x83,
-  kMkvFlagEnabled = 0xB9,
-  kMkvFlagDefault = 0x88,
-  kMkvFlagForced = 0x55AA,
-  kMkvFlagLacing = 0x9C,
-  kMkvDefaultDuration = 0x23E383,
-  kMkvMaxBlockAdditionID = 0x55EE,
-  kMkvName = 0x536E,
-  kMkvLanguage = 0x22B59C,
-  kMkvCodecID = 0x86,
-  kMkvCodecPrivate = 0x63A2,
-  kMkvCodecName = 0x258688,
-  kMkvCodecDelay = 0x56AA,
-  kMkvSeekPreRoll = 0x56BB,
-  // video
-  kMkvVideo = 0xE0,
-  kMkvFlagInterlaced = 0x9A,
-  kMkvStereoMode = 0x53B8,
-  kMkvAlphaMode = 0x53C0,
-  kMkvPixelWidth = 0xB0,
-  kMkvPixelHeight = 0xBA,
-  kMkvPixelCropBottom = 0x54AA,
-  kMkvPixelCropTop = 0x54BB,
-  kMkvPixelCropLeft = 0x54CC,
-  kMkvPixelCropRight = 0x54DD,
-  kMkvDisplayWidth = 0x54B0,
-  kMkvDisplayHeight = 0x54BA,
-  kMkvDisplayUnit = 0x54B2,
-  kMkvAspectRatioType = 0x54B3,
-  kMkvFrameRate = 0x2383E3,
-  // end video
-  // audio
-  kMkvAudio = 0xE1,
-  kMkvSamplingFrequency = 0xB5,
-  kMkvOutputSamplingFrequency = 0x78B5,
-  kMkvChannels = 0x9F,
-  kMkvBitDepth = 0x6264,
-  // end audio
-  // ContentEncodings
-  kMkvContentEncodings = 0x6D80,
-  kMkvContentEncoding = 0x6240,
-  kMkvContentEncodingOrder = 0x5031,
-  kMkvContentEncodingScope = 0x5032,
-  kMkvContentEncodingType = 0x5033,
-  kMkvContentCompression = 0x5034,
-  kMkvContentCompAlgo = 0x4254,
-  kMkvContentCompSettings = 0x4255,
-  kMkvContentEncryption = 0x5035,
-  kMkvContentEncAlgo = 0x47E1,
-  kMkvContentEncKeyID = 0x47E2,
-  kMkvContentSignature = 0x47E3,
-  kMkvContentSigKeyID = 0x47E4,
-  kMkvContentSigAlgo = 0x47E5,
-  kMkvContentSigHashAlgo = 0x47E6,
-  kMkvContentEncAESSettings = 0x47E7,
-  kMkvAESSettingsCipherMode = 0x47E8,
-  kMkvAESSettingsCipherInitData = 0x47E9,
-  // end ContentEncodings
-  // Cueing Data
-  kMkvCues = 0x1C53BB6B,
-  kMkvCuePoint = 0xBB,
-  kMkvCueTime = 0xB3,
-  kMkvCueTrackPositions = 0xB7,
-  kMkvCueTrack = 0xF7,
-  kMkvCueClusterPosition = 0xF1,
-  kMkvCueBlockNumber = 0x5378,
-  // Chapters
-  kMkvChapters = 0x1043A770,
-  kMkvEditionEntry = 0x45B9,
-  kMkvChapterAtom = 0xB6,
-  kMkvChapterUID = 0x73C4,
-  kMkvChapterStringUID = 0x5654,
-  kMkvChapterTimeStart = 0x91,
-  kMkvChapterTimeEnd = 0x92,
-  kMkvChapterDisplay = 0x80,
-  kMkvChapString = 0x85,
-  kMkvChapLanguage = 0x437C,
-  kMkvChapCountry = 0x437E,
-  // Tags
-  kMkvTags = 0x1254C367,
-  kMkvTag = 0x7373,
-  kMkvSimpleTag = 0x67C8,
-  kMkvTagName = 0x45A3,
-  kMkvTagString = 0x4487
-};
-
-}  // end namespace mkvmuxer
-
-#endif  // WEBMIDS_HPP
--- 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 {
 
--- 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;