diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index 3265ff939a0434b6dc3f1cb81bd76f17a7e7fe5b..75921aa028bf8b9e7012e9c514d1ff1f1899d293 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -169,6 +169,7 @@ void EncoderTest::RunLoop(VideoSource *video) {
       bool has_cxdata = false;
       bool has_dxdata = false;
       while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
+        pkt = MutateEncoderOutputHook(pkt);
         again = true;
         switch (pkt->kind) {
           case VPX_CODEC_CX_FRAME_PKT:
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h
index 35082a7fdac2e42729595e0ca317eb8ecb496a7b..5a37816ab941b5b8288d11da1e99f57fffda686d 100644
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -203,6 +203,12 @@ class EncoderTest {
   virtual void DecompressedFrameHook(const vpx_image_t& img,
                                      vpx_codec_pts_t pts) {}
 
+  // Hook that can modify the encoder's output data
+  virtual const vpx_codec_cx_pkt_t * MutateEncoderOutputHook(
+      const vpx_codec_cx_pkt_t *pkt) {
+    return pkt;
+  }
+
   bool                 abort_;
   vpx_codec_enc_cfg_t  cfg_;
   unsigned int         passes_;
diff --git a/test/superframe_test.cc b/test/superframe_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..39190ea78abe4acf87d87d630ab988058e56b2ad
--- /dev/null
+++ b/test/superframe_test.cc
@@ -0,0 +1,100 @@
+/*
+ *  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 <climits>
+#include "third_party/googletest/src/include/gtest/gtest.h"
+#include "test/codec_factory.h"
+#include "test/encode_test_driver.h"
+#include "test/i420_video_source.h"
+#include "test/util.h"
+
+namespace {
+
+class SuperframeTest : public ::libvpx_test::EncoderTest,
+    public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
+ protected:
+  SuperframeTest() : EncoderTest(GET_PARAM(0)), modified_buf_(NULL),
+      last_sf_pts_(0) {}
+
+  virtual void SetUp() {
+    InitializeConfig();
+    SetMode(GET_PARAM(1));
+    sf_count_ = 0;
+    sf_count_max_ = INT_MAX;
+  }
+
+  virtual void TearDown() {
+    delete modified_buf_;
+  }
+
+  virtual bool Continue() const {
+    return !HasFatalFailure() && !abort_;
+  }
+
+  virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
+                                  libvpx_test::Encoder *encoder) {
+    if (video->frame() == 1) {
+      encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
+    }
+  }
+
+  virtual const vpx_codec_cx_pkt_t * MutateEncoderOutputHook(
+      const vpx_codec_cx_pkt_t *pkt) {
+    if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
+      return pkt;
+
+    const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
+    const uint8_t marker = buffer[pkt->data.frame.sz - 1];
+    const int frames = (marker & 0x7) + 1;
+    const int mag = ((marker >> 3) & 3) + 1;
+    const unsigned int index_sz = 2 + mag  * frames;
+    if ((marker & 0xf0) == 0xc0 &&
+        pkt->data.frame.sz >= index_sz &&
+        buffer[pkt->data.frame.sz - index_sz] == marker) {
+      // frame is a superframe. strip off the index.
+      if (modified_buf_)
+        delete modified_buf_;
+      modified_buf_ = new uint8_t[pkt->data.frame.sz - index_sz];
+      memcpy(modified_buf_, pkt->data.frame.buf,
+             pkt->data.frame.sz - index_sz);
+      modified_pkt_ = *pkt;
+      modified_pkt_.data.frame.buf = modified_buf_;
+      modified_pkt_.data.frame.sz -= index_sz;
+
+      sf_count_++;
+      last_sf_pts_ = pkt->data.frame.pts;
+      return &modified_pkt_;
+    }
+
+    // Make sure we do a few frames after the last SF
+    abort_ |= sf_count_ > sf_count_max_ &&
+              pkt->data.frame.pts - last_sf_pts_ >= 5;
+    return pkt;
+  }
+
+  int sf_count_;
+  int sf_count_max_;
+  vpx_codec_cx_pkt_t modified_pkt_;
+  uint8_t *modified_buf_;
+  vpx_codec_pts_t last_sf_pts_;
+};
+
+TEST_P(SuperframeTest, TestSuperframeIndexIsOptional) {
+  sf_count_max_ = 0;  // early exit on successful test.
+  cfg_.g_lag_in_frames = 25;
+
+  ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+                                       30, 1, 0, 40);
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+  EXPECT_EQ(sf_count_, 1);
+}
+
+VP9_INSTANTIATE_TEST_CASE(SuperframeTest, ::testing::Values(
+    ::libvpx_test::kTwoPassGood));
+}  // namespace
diff --git a/test/test.mk b/test/test.mk
index f7a1462673ce7a3f0793a8ceaa65a2ec7451a42c..37e4ee793a1c62f950ceee406945b40a0e18f94e 100644
--- a/test/test.mk
+++ b/test/test.mk
@@ -68,6 +68,7 @@ LIBVPX_TEST_SRCS-yes                   += vp9_boolcoder_test.cc
 
 # IDCT test currently depends on FDCT function
 LIBVPX_TEST_SRCS-yes                   += idct8x8_test.cc
+LIBVPX_TEST_SRCS-yes                   += superframe_test.cc
 LIBVPX_TEST_SRCS-yes                   += tile_independence_test.cc
 endif
 
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index 6335827cfcd7be7b09b5cc3134c033401c7afd69..1d9e7a4e99ba1a57958dec1943bce083922898d9 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -4009,7 +4009,7 @@ int vp9_get_preview_raw_frame(VP9_PTR comp, YV12_BUFFER_CONFIG *dest,
                               vp9_ppflags_t *flags) {
   VP9_COMP *cpi = (VP9_COMP *) comp;
 
-  if (cpi->refresh_alt_ref_frame)
+  if (!cpi->common.show_frame)
     return -1;
   else {
     int ret;
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index db7a2fd11a463f2b8aa9ab42d7ba73bde198982f..724f4185fbc64f07328e5b9417d4da07401eabdb 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -77,6 +77,9 @@ struct vpx_codec_alg_priv {
   unsigned int            cx_data_sz;
   unsigned char          *pending_cx_data;
   unsigned int            pending_cx_data_sz;
+  int                     pending_frame_count;
+  uint32_t                pending_frame_sizes[8];
+  uint32_t                pending_frame_magnitude;
   vpx_image_t             preview_img;
   vp8_postproc_cfg_t      preview_ppcfg;
   vpx_codec_pkt_list_decl(64) pkt_list;              // changed to accomendate the maximum number of lagged frames allowed
@@ -579,6 +582,45 @@ static void pick_quickcompress_mode(vpx_codec_alg_priv_t  *ctx,
 }
 
 
+static void write_superframe_index(vpx_codec_alg_priv_t *ctx) {
+  uint8_t marker = 0xc0;
+  int mag, mask, index_sz;
+
+  assert(ctx->pending_frame_count);
+  assert(ctx->pending_frame_count <= 8);
+
+  /* Add the number of frames to the marker byte */
+  marker |= ctx->pending_frame_count - 1;
+
+  /* Choose the magnitude */
+  for (mag = 0, mask = 0xff; mag < 4; mag++) {
+    if (ctx->pending_frame_magnitude < mask)
+      break;
+    mask <<= 8;
+    mask |= 0xff;
+  }
+  marker |= mag << 3;
+
+  /* Write the index */
+  index_sz = 2 + (mag + 1) * ctx->pending_frame_count;
+  if (ctx->pending_cx_data_sz + index_sz < ctx->cx_data_sz) {
+    uint8_t *x = ctx->pending_cx_data + ctx->pending_cx_data_sz;
+    int i, j;
+
+    *x++ = marker;
+    for (i = 0; i < ctx->pending_frame_count; i++) {
+      int this_sz = ctx->pending_frame_sizes[i];
+
+      for (j = 0; j <= mag; j++) {
+        *x++ = this_sz & 0xff;
+        this_sz >>= 8;
+      }
+    }
+    *x++ = marker;
+    ctx->pending_cx_data_sz += index_sz;
+  }
+}
+
 static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
                                    const vpx_image_t     *img,
                                    vpx_codec_pts_t        pts,
@@ -712,6 +754,8 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
           if (!ctx->pending_cx_data)
             ctx->pending_cx_data = cx_data;
           ctx->pending_cx_data_sz += size;
+          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
+          ctx->pending_frame_magnitude |= size;
           cx_data += size;
           cx_data_sz -= size;
           continue;
@@ -771,10 +815,16 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
         else*/
         {
           if (ctx->pending_cx_data) {
+            ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
+            ctx->pending_frame_magnitude |= size;
+            ctx->pending_cx_data_sz += size;
+            write_superframe_index(ctx);
             pkt.data.frame.buf = ctx->pending_cx_data;
-            pkt.data.frame.sz  = ctx->pending_cx_data_sz + size;
+            pkt.data.frame.sz  = ctx->pending_cx_data_sz;
             ctx->pending_cx_data = NULL;
             ctx->pending_cx_data_sz = 0;
+            ctx->pending_frame_count = 0;
+            ctx->pending_frame_magnitude = 0;
           } else {
             pkt.data.frame.buf = cx_data;
             pkt.data.frame.sz  = size;
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index f2b80e1fbe894d2e3446f5f523622396859f5a5a..1bda1703f1303a21afef58b5548b79c4338de5d3 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -425,6 +425,39 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t  *ctx,
   return res;
 }
 
+static void parse_superframe_index(const uint8_t *data,
+                                   size_t         data_sz,
+                                   uint32_t       sizes[8],
+                                   int           *count) {
+  uint8_t marker;
+
+  assert(data_sz);
+  marker = data[data_sz - 1];
+  *count = 0;
+
+  if ((marker & 0xf0) == 0xc0) {
+    const int frames = (marker & 0x7) + 1;
+    const int mag = ((marker >> 3) & 3) + 1;
+    const int index_sz = 2 + mag  * frames;
+
+    if (data_sz >= index_sz && data[data_sz - index_sz] == marker) {
+      // found a valid superframe index
+      int i, j;
+      const uint8_t *x = data + data_sz - index_sz + 1;
+
+      for (i = 0; i < frames; i++) {
+        int this_sz = 0;
+
+        for (j = 0; j < mag; j++)
+          this_sz |= (*x++) << (j * 8);
+        sizes[i] = this_sz;
+      }
+
+      *count = frames;
+    }
+  }
+}
+
 static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t  *ctx,
                                   const uint8_t         *data,
                                   unsigned int           data_sz,
@@ -433,8 +466,42 @@ static vpx_codec_err_t vp9_decode(vpx_codec_alg_priv_t  *ctx,
   const uint8_t *data_start = data;
   const uint8_t *data_end = data + data_sz;
   vpx_codec_err_t res = 0;
+  uint32_t sizes[8];
+  int frames_this_pts, frame_count = 0;
+
+  parse_superframe_index(data, data_sz, sizes, &frames_this_pts);
 
   do {
+    // Skip over the superframe index, if present
+    if (data_sz && (*data_start & 0xf0) == 0xc0) {
+      const uint8_t marker = *data_start;
+      const int frames = (marker & 0x7) + 1;
+      const int mag = ((marker >> 3) & 3) + 1;
+      const int index_sz = 2 + mag  * frames;
+
+      if (data_sz >= index_sz && data_start[index_sz - 1] == marker) {
+        data_start += index_sz;
+        data_sz -= index_sz;
+        if (data_start < data_end)
+          continue;
+        else
+          break;
+      }
+    }
+
+    // Use the correct size for this frame, if an index is present.
+    if (frames_this_pts) {
+      uint32_t this_sz = sizes[frame_count];
+
+      if (data_sz < this_sz) {
+        ctx->base.err_detail = "Invalid frame size in index";
+        return VPX_CODEC_CORRUPT_FRAME;
+      }
+
+      data_sz = this_sz;
+      frame_count++;
+    }
+
     res = decode_one(ctx, &data_start, data_sz, user_priv, deadline);
     assert(data_start >= data);
     assert(data_start <= data_end);