shithub: libvpx

Download patch

ref: 80577dff4b409c30c7bb638a561787ec2c0a0210
parent: 88690475ea28fb396c8efb01ab6d21e106765341
author: Paul Wilkins <paulwilkins@google.com>
date: Wed Apr 2 00:08:18 EDT 2014

Revert "Changing webmenc to use libwebm"

Temporary revert.
Problems with conflicting definitions of type off_t
in MSVC builds that need resolving.

c:\Program Files (x86)\
  Microsoft Visual Studio 9.0\VC\include\wchar.h(479) :
  "error C2371: 'off_t' : redefinition; different basic types
c:\on2experimental\libvpx\tools_common.h(26) :
   see declaration of 'off_t'"

This reverts commit 92a4c591122fa406a1d7aed834a5283a86d9758a.

Change-Id: I535e40a18842a92e3e6e0b29e5fba66313010803

--- a/build/make/Makefile
+++ b/build/make/Makefile
@@ -147,15 +147,6 @@
 	$(if $(quiet),@echo "    [CXX] $@")
 	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
 
-$(BUILD_PFX)%.cpp.d: %.cpp
-	$(if $(quiet),@echo "    [DEP] $@")
-	$(qexec)mkdir -p $(dir $@)
-	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -M $< | $(fmt_deps) > $@
-
-$(BUILD_PFX)%.cpp.o: %.cpp
-	$(if $(quiet),@echo "    [CXX] $@")
-	$(qexec)$(CXX) $(INTERNAL_CFLAGS) $(CXXFLAGS) -c -o $@ $<
-
 $(BUILD_PFX)%.asm.d: %.asm
 	$(if $(quiet),@echo "    [DEP] $@")
 	$(qexec)mkdir -p $(dir $@)
@@ -227,7 +218,7 @@
 
 find_file1=$(word 1,$(wildcard $(subst //,/,$(addsuffix /$(1),$(2)))))
 find_file=$(foreach f,$(1),$(call find_file1,$(strip $(f)),$(strip $(2))) )
-obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o .cpp=.cpp.o
+obj_pats=.c=.c.o $(AS_SFX)=$(AS_SFX).o .cc=.cc.o
 objs=$(addprefix $(BUILD_PFX),$(foreach p,$(obj_pats),$(filter %.o,$(1:$(p))) ))
 
 install_map_templates=$(eval $(call install_map_template,$(1),$(2)))
--- a/configure
+++ b/configure
@@ -704,11 +704,13 @@
         enabled postproc || die "postproc_visualizer requires postproc to be enabled"
     fi
 
+    # Enable WebM IO by default.
+    soft_enable webm_io
+
     # Enable unit tests by default if we have a working C++ compiler.
     case "$toolchain" in
         *-vs*)
             soft_enable unit_tests
-            soft_enable webm_io
         ;;
         *-android-*)
             # GTestLog must be modified to use Android logging utilities.
@@ -724,21 +726,13 @@
             check_cxx "$@" <<EOF && soft_enable unit_tests
 int z;
 EOF
-            check_cxx "$@" <<EOF && soft_enable webm_io
-int z;
-EOF
         ;;
         *)
             enabled pthread_h && check_cxx "$@" <<EOF && soft_enable unit_tests
 int z;
 EOF
-            check_cxx "$@" <<EOF && soft_enable webm_io
-int z;
-EOF
         ;;
     esac
-    # libwebm needs to be linked with C++ standard library
-    enabled webm_io && LD=${CXX}
 }
 
 
--- a/examples.mk
+++ b/examples.mk
@@ -15,16 +15,6 @@
                 third_party/libyuv/source/scale.c  \
                 third_party/libyuv/source/cpu_id.c
 
-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 \
-                      third_party/libwebm/webmids.hpp
-
 # List of examples to build. UTILS are tools meant for distribution
 # while EXAMPLES demonstrate specific portions of the API.
 UTILS-$(CONFIG_DECODERS)    += vpxdec.c
@@ -63,8 +53,10 @@
 vpxenc.SRCS                 += vpxstats.c vpxstats.h
 vpxenc.SRCS                 += $(LIBYUV_SRCS)
 ifeq ($(CONFIG_WEBM_IO),yes)
-  vpxenc.SRCS                 += $(LIBWEBM_MUXER_SRCS)
-  vpxenc.SRCS                 += webmenc.cc webmenc.h
+  vpxenc.SRCS                 += third_party/libmkv/EbmlIDs.h
+  vpxenc.SRCS                 += third_party/libmkv/EbmlWriter.c
+  vpxenc.SRCS                 += third_party/libmkv/EbmlWriter.h
+  vpxenc.SRCS                 += webmenc.c webmenc.h
 endif
 vpxenc.GUID                  = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
 vpxenc.DESCRIPTION           = Full featured encoder
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -123,6 +123,55 @@
   return 0;
 }
 
+#if CONFIG_WEBM_IO
+/* Murmur hash derived from public domain reference implementation at
+ *   http:// sites.google.com/site/murmurhash/
+ */
+static unsigned int murmur(const void *key, int len, unsigned int seed) {
+  const unsigned int m = 0x5bd1e995;
+  const int r = 24;
+
+  unsigned int h = seed ^ len;
+
+  const unsigned char *data = (const unsigned char *)key;
+
+  while (len >= 4) {
+    unsigned int k;
+
+    k  = (unsigned int)data[0];
+    k |= (unsigned int)data[1] << 8;
+    k |= (unsigned int)data[2] << 16;
+    k |= (unsigned int)data[3] << 24;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h *= m;
+    h ^= k;
+
+    data += 4;
+    len -= 4;
+  }
+
+  switch (len) {
+    case 3:
+      h ^= data[2] << 16;
+    case 2:
+      h ^= data[1] << 8;
+    case 1:
+      h ^= data[0];
+      h *= m;
+  };
+
+  h ^= h >> 13;
+  h *= m;
+  h ^= h >> 15;
+
+  return h;
+}
+#endif  // CONFIG_WEBM_IO
+
 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0,
                                            "Debug mode (makes output deterministic)");
 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
@@ -565,6 +614,7 @@
   FILE                     *file;
   struct rate_hist         *rate_hist;
   struct EbmlGlobal         ebml;
+  uint32_t                  hash;
   uint64_t                  psnr_sse_total;
   uint64_t                  psnr_samples_total;
   double                    psnr_totals[4];
@@ -786,9 +836,7 @@
     stream->config.stereo_fmt = STEREO_FORMAT_MONO;
     stream->config.write_webm = 1;
 #if CONFIG_WEBM_IO
-    stream->ebml.last_pts_ns = -1;
-    stream->ebml.writer = NULL;
-    stream->ebml.segment = NULL;
+    stream->ebml.last_pts_ms = -1;
 #endif
 
     /* Allows removal of the application version from the EBML tags */
@@ -1123,7 +1171,9 @@
 
 #if CONFIG_WEBM_IO
   if (stream->config.write_webm) {
-    write_webm_file_footer(&stream->ebml);
+    write_webm_file_footer(&stream->ebml, stream->hash);
+    free(stream->ebml.cue_list);
+    stream->ebml.cue_list = NULL;
   }
 #endif
 
@@ -1279,6 +1329,12 @@
         update_rate_histogram(stream->rate_hist, cfg, pkt);
 #if CONFIG_WEBM_IO
         if (stream->config.write_webm) {
+          /* Update the hash */
+          if (!stream->ebml.debug)
+            stream->hash = murmur(pkt->data.frame.buf,
+                                  (int)pkt->data.frame.sz,
+                                  stream->hash);
+
           write_webm_block(&stream->ebml, cfg, pkt);
         }
 #endif
--- /dev/null
+++ b/webmenc.c
@@ -1,0 +1,331 @@
+/*
+ *  Copyright (c) 2013 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 "webmenc.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include "third_party/libmkv/EbmlWriter.h"
+#include "third_party/libmkv/EbmlIDs.h"
+
+void Ebml_Write(struct EbmlGlobal *glob,
+                const void *buffer_in,
+                unsigned long len) {
+  (void) fwrite(buffer_in, 1, len, glob->stream);
+}
+
+#define WRITE_BUFFER(s) \
+for (i = len - 1; i >= 0; i--) { \
+  x = (char)(*(const s *)buffer_in >> (i * CHAR_BIT)); \
+  Ebml_Write(glob, &x, 1); \
+}
+
+void Ebml_Serialize(struct EbmlGlobal *glob,
+                    const void *buffer_in,
+                    int buffer_size,
+                    unsigned long len) {
+  char x;
+  int i;
+
+  /* buffer_size:
+   * 1 - int8_t;
+   * 2 - int16_t;
+   * 3 - int32_t;
+   * 4 - int64_t;
+   */
+  switch (buffer_size) {
+    case 1:
+      WRITE_BUFFER(int8_t)
+      break;
+    case 2:
+      WRITE_BUFFER(int16_t)
+      break;
+    case 4:
+      WRITE_BUFFER(int32_t)
+      break;
+    case 8:
+      WRITE_BUFFER(int64_t)
+      break;
+    default:
+      break;
+  }
+}
+#undef WRITE_BUFFER
+
+/* Need a fixed size serializer for the track ID. libmkv provides a 64 bit
+ * one, but not a 32 bit one.
+ */
+static void Ebml_SerializeUnsigned32(struct EbmlGlobal *glob,
+                                     unsigned int class_id,
+                                     uint64_t ui) {
+  const unsigned char sizeSerialized = 4 | 0x80;
+  Ebml_WriteID(glob, class_id);
+  Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
+  Ebml_Serialize(glob, &ui, sizeof(ui), 4);
+}
+
+static void Ebml_StartSubElement(struct EbmlGlobal *glob,
+                                 EbmlLoc *ebmlLoc,
+                                 unsigned int class_id) {
+  const uint64_t kEbmlUnknownLength = LITERALU64(0x01FFFFFF, 0xFFFFFFFF);
+  Ebml_WriteID(glob, class_id);
+  *ebmlLoc = ftello(glob->stream);
+  Ebml_Serialize(glob, &kEbmlUnknownLength, sizeof(kEbmlUnknownLength), 8);
+}
+
+static void Ebml_EndSubElement(struct EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
+  off_t pos;
+  uint64_t size;
+
+  /* Save the current stream pointer. */
+  pos = ftello(glob->stream);
+
+  /* Calculate the size of this element. */
+  size = pos - *ebmlLoc - 8;
+  size |= LITERALU64(0x01000000, 0x00000000);
+
+  /* Seek back to the beginning of the element and write the new size. */
+  fseeko(glob->stream, *ebmlLoc, SEEK_SET);
+  Ebml_Serialize(glob, &size, sizeof(size), 8);
+
+  /* Reset the stream pointer. */
+  fseeko(glob->stream, pos, SEEK_SET);
+}
+
+void write_webm_seek_element(struct EbmlGlobal *ebml,
+                             unsigned int id,
+                             off_t pos) {
+  uint64_t offset = pos - ebml->position_reference;
+  EbmlLoc start;
+  Ebml_StartSubElement(ebml, &start, Seek);
+  Ebml_SerializeBinary(ebml, SeekID, id);
+  Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
+  Ebml_EndSubElement(ebml, &start);
+}
+
+void write_webm_seek_info(struct EbmlGlobal *ebml) {
+  off_t pos;
+  EbmlLoc start;
+  EbmlLoc startInfo;
+  uint64_t frame_time;
+  char version_string[64];
+
+  /* Save the current stream pointer. */
+  pos = ftello(ebml->stream);
+
+  if (ebml->seek_info_pos)
+    fseeko(ebml->stream, ebml->seek_info_pos, SEEK_SET);
+  else
+    ebml->seek_info_pos = pos;
+
+  Ebml_StartSubElement(ebml, &start, SeekHead);
+  write_webm_seek_element(ebml, Tracks, ebml->track_pos);
+  write_webm_seek_element(ebml, Cues, ebml->cue_pos);
+  write_webm_seek_element(ebml, Info, ebml->segment_info_pos);
+  Ebml_EndSubElement(ebml, &start);
+
+  /* Create and write the Segment Info. */
+  if (ebml->debug) {
+    strcpy(version_string, "vpxenc");
+  } else {
+    strcpy(version_string, "vpxenc ");
+    strncat(version_string,
+            vpx_codec_version_str(),
+            sizeof(version_string) - 1 - strlen(version_string));
+  }
+
+  frame_time = (uint64_t)1000 * ebml->framerate.den
+               / ebml->framerate.num;
+  ebml->segment_info_pos = ftello(ebml->stream);
+  Ebml_StartSubElement(ebml, &startInfo, Info);
+  Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
+  Ebml_SerializeFloat(ebml, Segment_Duration,
+                      (double)(ebml->last_pts_ms + frame_time));
+  Ebml_SerializeString(ebml, 0x4D80, version_string);
+  Ebml_SerializeString(ebml, 0x5741, version_string);
+  Ebml_EndSubElement(ebml, &startInfo);
+}
+
+void write_webm_file_header(struct EbmlGlobal *glob,
+                            const vpx_codec_enc_cfg_t *cfg,
+                            const struct vpx_rational *fps,
+                            stereo_format_t stereo_fmt,
+                            unsigned int fourcc) {
+  EbmlLoc start;
+  EbmlLoc trackStart;
+  EbmlLoc videoStart;
+  unsigned int trackNumber = 1;
+  uint64_t trackID = 0;
+  unsigned int pixelWidth = cfg->g_w;
+  unsigned int pixelHeight = cfg->g_h;
+
+  /* Write the EBML header. */
+  Ebml_StartSubElement(glob, &start, EBML);
+  Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
+  Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1);
+  Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4);
+  Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8);
+  Ebml_SerializeString(glob, DocType, "webm");
+  Ebml_SerializeUnsigned(glob, DocTypeVersion, 2);
+  Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2);
+  Ebml_EndSubElement(glob, &start);
+
+  /* Open and begin writing the segment element. */
+  Ebml_StartSubElement(glob, &glob->startSegment, Segment);
+  glob->position_reference = ftello(glob->stream);
+  glob->framerate = *fps;
+  write_webm_seek_info(glob);
+
+  /* Open and write the Tracks element. */
+  glob->track_pos = ftello(glob->stream);
+  Ebml_StartSubElement(glob, &trackStart, Tracks);
+
+  /* Open and write the Track entry. */
+  Ebml_StartSubElement(glob, &start, TrackEntry);
+  Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+  glob->track_id_pos = ftello(glob->stream);
+  Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
+  Ebml_SerializeUnsigned(glob, TrackType, 1);
+  Ebml_SerializeString(glob, CodecID,
+                       fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
+  Ebml_StartSubElement(glob, &videoStart, Video);
+  Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
+  Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
+  Ebml_SerializeUnsigned(glob, StereoMode, stereo_fmt);
+  Ebml_EndSubElement(glob, &videoStart);
+
+  /* Close Track entry. */
+  Ebml_EndSubElement(glob, &start);
+
+  /* Close Tracks element. */
+  Ebml_EndSubElement(glob, &trackStart);
+
+  /* Segment element remains open. */
+}
+
+void write_webm_block(struct EbmlGlobal *glob,
+                      const vpx_codec_enc_cfg_t *cfg,
+                      const vpx_codec_cx_pkt_t *pkt) {
+  unsigned int block_length;
+  unsigned char track_number;
+  uint16_t block_timecode = 0;
+  unsigned char flags;
+  int64_t pts_ms;
+  int start_cluster = 0, is_keyframe;
+
+  /* Calculate the PTS of this frame in milliseconds. */
+  pts_ms = pkt->data.frame.pts * 1000
+           * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
+
+  if (pts_ms <= glob->last_pts_ms)
+    pts_ms = glob->last_pts_ms + 1;
+
+  glob->last_pts_ms = pts_ms;
+
+  /* Calculate the relative time of this block. */
+  if (pts_ms - glob->cluster_timecode > SHRT_MAX)
+    start_cluster = 1;
+  else
+    block_timecode = (uint16_t)pts_ms - glob->cluster_timecode;
+
+  is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
+  if (start_cluster || is_keyframe) {
+    if (glob->cluster_open)
+      Ebml_EndSubElement(glob, &glob->startCluster);
+
+    /* Open the new cluster. */
+    block_timecode = 0;
+    glob->cluster_open = 1;
+    glob->cluster_timecode = (uint32_t)pts_ms;
+    glob->cluster_pos = ftello(glob->stream);
+    Ebml_StartSubElement(glob, &glob->startCluster, Cluster);
+    Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);
+
+    /* Save a cue point if this is a keyframe. */
+    if (is_keyframe) {
+      struct cue_entry *cue, *new_cue_list;
+
+      new_cue_list = realloc(glob->cue_list,
+                             (glob->cues + 1) * sizeof(struct cue_entry));
+      if (new_cue_list)
+        glob->cue_list = new_cue_list;
+      else
+        fatal("Failed to realloc cue list.");
+
+      cue = &glob->cue_list[glob->cues];
+      cue->time = glob->cluster_timecode;
+      cue->loc = glob->cluster_pos;
+      glob->cues++;
+    }
+  }
+
+  /* Write the Simple Block. */
+  Ebml_WriteID(glob, SimpleBlock);
+
+  block_length = (unsigned int)pkt->data.frame.sz + 4;
+  block_length |= 0x10000000;
+  Ebml_Serialize(glob, &block_length, sizeof(block_length), 4);
+
+  track_number = 1;
+  track_number |= 0x80;
+  Ebml_Write(glob, &track_number, 1);
+
+  Ebml_Serialize(glob, &block_timecode, sizeof(block_timecode), 2);
+
+  flags = 0;
+  if (is_keyframe)
+    flags |= 0x80;
+  if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
+    flags |= 0x08;
+  Ebml_Write(glob, &flags, 1);
+
+  Ebml_Write(glob, pkt->data.frame.buf, (unsigned int)pkt->data.frame.sz);
+}
+
+void write_webm_file_footer(struct EbmlGlobal *glob, int hash) {
+  EbmlLoc start_cues;
+  EbmlLoc start_cue_point;
+  EbmlLoc start_cue_tracks;
+  unsigned int i;
+
+  if (glob->cluster_open)
+    Ebml_EndSubElement(glob, &glob->startCluster);
+
+  glob->cue_pos = ftello(glob->stream);
+  Ebml_StartSubElement(glob, &start_cues, Cues);
+
+  for (i = 0; i < glob->cues; i++) {
+    struct cue_entry *cue = &glob->cue_list[i];
+    Ebml_StartSubElement(glob, &start_cue_point, CuePoint);
+    Ebml_SerializeUnsigned(glob, CueTime, cue->time);
+
+    Ebml_StartSubElement(glob, &start_cue_tracks, CueTrackPositions);
+    Ebml_SerializeUnsigned(glob, CueTrack, 1);
+    Ebml_SerializeUnsigned64(glob, CueClusterPosition,
+                             cue->loc - glob->position_reference);
+    Ebml_EndSubElement(glob, &start_cue_tracks);
+
+    Ebml_EndSubElement(glob, &start_cue_point);
+  }
+
+  Ebml_EndSubElement(glob, &start_cues);
+
+  /* Close the Segment. */
+  Ebml_EndSubElement(glob, &glob->startSegment);
+
+  /* Patch up the seek info block. */
+  write_webm_seek_info(glob);
+
+  /* Patch up the track id. */
+  fseeko(glob->stream, glob->track_id_pos, SEEK_SET);
+  Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
+
+  fseeko(glob->stream, 0, SEEK_END);
+}
--- a/webmenc.cc
+++ /dev/null
@@ -1,86 +1,0 @@
-/*
- *  Copyright (c) 2014 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 "./webmenc.h"
-
-#include <string>
-
-#include "third_party/libwebm/mkvmuxer.hpp"
-#include "third_party/libwebm/mkvmuxerutil.hpp"
-#include "third_party/libwebm/mkvwriter.hpp"
-
-namespace {
-const uint64_t kDebugTrackUid = 0xDEADBEEF;
-const int kVideoTrackNumber = 1;
-}  // namespace
-
-void write_webm_file_header(struct EbmlGlobal *glob,
-                            const vpx_codec_enc_cfg_t *cfg,
-                            const struct vpx_rational *fps,
-                            stereo_format_t stereo_fmt,
-                            unsigned int fourcc) {
-  mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(glob->stream);
-  mkvmuxer::Segment *const segment = new mkvmuxer::Segment();
-  segment->Init(writer);
-  segment->set_mode(mkvmuxer::Segment::kFile);
-  segment->OutputCues(true);
-
-  mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo();
-  const uint64_t kTimecodeScale = 1000000;
-  info->set_timecode_scale(kTimecodeScale);
-  std::string version = "vpxenc";
-  if (!glob->debug) {
-    version.append(std::string(" ") + vpx_codec_version_str());
-  }
-  info->set_writing_app(version.c_str());
-
-  const int video_track_id = segment->AddVideoTrack(static_cast<int>(cfg->g_w),
-                                                    static_cast<int>(cfg->g_h),
-                                                    kVideoTrackNumber);
-  mkvmuxer::VideoTrack* const video_track =
-      static_cast<mkvmuxer::VideoTrack*>(
-          segment->GetTrackByNumber(video_track_id));
-  video_track->SetStereoMode(stereo_fmt);
-  video_track->set_codec_id(fourcc == VP8_FOURCC ? "V_VP8" : "V_VP9");
-  if (glob->debug) {
-    video_track->set_uid(kDebugTrackUid);
-  }
-  glob->writer = writer;
-  glob->segment = segment;
-}
-
-void write_webm_block(struct EbmlGlobal *glob,
-                      const vpx_codec_enc_cfg_t *cfg,
-                      const vpx_codec_cx_pkt_t *pkt) {
-  mkvmuxer::Segment *const segment =
-      reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
-  int64_t pts_ns = pkt->data.frame.pts * 1000000000ll *
-                   cfg->g_timebase.num / cfg->g_timebase.den;
-  if (pts_ns <= glob->last_pts_ns)
-    pts_ns = glob->last_pts_ns + 1000000;
-  glob->last_pts_ns = pts_ns;
-
-  segment->AddFrame(static_cast<uint8_t*>(pkt->data.frame.buf),
-                    pkt->data.frame.sz,
-                    kVideoTrackNumber,
-                    pts_ns,
-                    pkt->data.frame.flags & VPX_FRAME_IS_KEY);
-}
-
-void write_webm_file_footer(struct EbmlGlobal *glob) {
-  mkvmuxer::MkvWriter *const writer =
-      reinterpret_cast<mkvmuxer::MkvWriter*>(glob->writer);
-  mkvmuxer::Segment *const segment =
-      reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
-  segment->Finalize();
-  delete segment;
-  delete writer;
-  glob->writer = NULL;
-  glob->segment = NULL;
-}
--- a/webmenc.h
+++ b/webmenc.h
@@ -13,6 +13,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#if defined(_MSC_VER)
+/* MSVS doesn't define off_t */
+typedef __int64 off_t;
+#else
+#include <stdint.h>
+#endif
+
 #include "tools_common.h"
 #include "vpx/vpx_encoder.h"
 
@@ -20,13 +27,40 @@
 extern "C" {
 #endif
 
-/* TODO(vigneshv): Rename this struct */
+typedef off_t EbmlLoc;
+
+struct cue_entry {
+  unsigned int time;
+  uint64_t loc;
+};
+
 struct EbmlGlobal {
   int debug;
+
   FILE *stream;
-  int64_t last_pts_ns;
-  void *writer;
-  void *segment;
+  int64_t last_pts_ms;
+  vpx_rational_t framerate;
+
+  /* These pointers are to the start of an element */
+  off_t position_reference;
+  off_t seek_info_pos;
+  off_t segment_info_pos;
+  off_t track_pos;
+  off_t cue_pos;
+  off_t cluster_pos;
+
+  /* This pointer is to a specific element to be serialized */
+  off_t track_id_pos;
+
+  /* These pointers are to the size field of the element */
+  EbmlLoc startSegment;
+  EbmlLoc startCluster;
+
+  uint32_t cluster_timecode;
+  int cluster_open;
+
+  struct cue_entry *cue_list;
+  unsigned int cues;
 };
 
 /* Stereo 3D packed frame format */
@@ -38,6 +72,10 @@
   STEREO_FORMAT_RIGHT_LEFT = 11
 } stereo_format_t;
 
+void write_webm_seek_element(struct EbmlGlobal *ebml,
+                             unsigned int id,
+                             off_t pos);
+
 void write_webm_file_header(struct EbmlGlobal *glob,
                             const vpx_codec_enc_cfg_t *cfg,
                             const struct vpx_rational *fps,
@@ -48,7 +86,7 @@
                       const vpx_codec_enc_cfg_t *cfg,
                       const vpx_codec_cx_pkt_t *pkt);
 
-void write_webm_file_footer(struct EbmlGlobal *glob);
+void write_webm_file_footer(struct EbmlGlobal *glob, int hash);
 
 #ifdef __cplusplus
 }  // extern "C"