diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h
index 862307ebbd9c0d2a4c432f1a08555a84f653a8b3..d366b9b1be31eeb6987aaa276e52a7a89ce244cb 100644
--- a/vp8/common/onyxc_int.h
+++ b/vp8/common/onyxc_int.h
@@ -35,6 +35,8 @@ void vp8_initialize_common(void);
 
 #define NUM_YV12_BUFFERS 4
 
+#define MAX_PARTITIONS 9
+
 typedef struct frame_contexts
 {
     vp8_prob bmode_prob [VP8_BINTRAMODES-1];
diff --git a/vp8/common/onyxd.h b/vp8/common/onyxd.h
index cf16a26da1ea95befbce07b771fce4ada67b311e..8a4703a8bae49b042fbcf6b23f23758a30f974f1 100644
--- a/vp8/common/onyxd.h
+++ b/vp8/common/onyxd.h
@@ -33,6 +33,7 @@ extern "C"
         int     postprocess;
         int     max_threads;
         int     error_concealment;
+        int     input_partition;
     } VP8D_CONFIG;
     typedef enum
     {
diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c
index 00e001733f5dca1829a12f654727be5641a89a92..7537ec6488aa23218846f52d9b4262c9e7a2679b 100644
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -463,6 +463,40 @@ static unsigned int read_partition_size(const unsigned char *cx_size)
     return size;
 }
 
+static void setup_token_decoder_partition_input(VP8D_COMP *pbi)
+{
+    vp8_reader *bool_decoder = &pbi->bc2;
+    int part_idx = 1;
+
+    TOKEN_PARTITION multi_token_partition =
+            (TOKEN_PARTITION)vp8_read_literal(&pbi->bc, 2);
+    assert(vp8dx_bool_error(&pbi->bc) ||
+           multi_token_partition == pbi->common.multi_token_partition);
+    if (pbi->num_partitions > 2)
+    {
+        CHECK_MEM_ERROR(pbi->mbc, vpx_malloc((pbi->num_partitions - 1) *
+                                             sizeof(vp8_reader)));
+        bool_decoder = pbi->mbc;
+    }
+
+    for (; part_idx < pbi->num_partitions; ++part_idx)
+    {
+        if (vp8dx_start_decode(bool_decoder,
+                               pbi->partitions[part_idx],
+                               pbi->partition_sizes[part_idx]))
+            vpx_internal_error(&pbi->common.error, VPX_CODEC_MEM_ERROR,
+                               "Failed to allocate bool decoder %d",
+                               part_idx);
+
+        bool_decoder++;
+    }
+
+#if CONFIG_MULTITHREAD
+    /* Clamp number of decoder threads */
+    if (pbi->decoding_thread_count > pbi->num_partitions - 1)
+        pbi->decoding_thread_count = pbi->num_partitions - 1;
+#endif
+}
 
 static void setup_token_decoder(VP8D_COMP *pbi,
                                 const unsigned char *cx_data)
@@ -619,13 +653,19 @@ int vp8_decode_frame(VP8D_COMP *pbi)
     VP8_COMMON *const pc = & pbi->common;
     MACROBLOCKD *const xd  = & pbi->mb;
     const unsigned char *data = (const unsigned char *)pbi->Source;
-    const unsigned char *const data_end = data + pbi->source_sz;
+    const unsigned char *data_end = data + pbi->source_sz;
     ptrdiff_t first_partition_length_in_bytes;
 
     int mb_row;
     int i, j, k, l;
     const int *const mb_feature_data_bits = vp8_mb_feature_data_bits;
 
+    if (pbi->input_partition)
+    {
+        data = pbi->partitions[0];
+        data_end =  data + pbi->partition_sizes[0];
+    }
+
     /* start with no corruption of current frame */
     xd->corrupted = 0;
     pc->yv12_fb[pc->new_fb_idx].corrupted = 0;
@@ -841,7 +881,14 @@ int vp8_decode_frame(VP8D_COMP *pbi)
         }
     }
 
-    setup_token_decoder(pbi, data + first_partition_length_in_bytes);
+    if (pbi->input_partition)
+    {
+        setup_token_decoder_partition_input(pbi);
+    }
+    else
+    {
+        setup_token_decoder(pbi, data + first_partition_length_in_bytes);
+    }
     xd->current_bc = &pbi->bc2;
 
     /* Read the default quantizers. */
@@ -930,10 +977,8 @@ int vp8_decode_frame(VP8D_COMP *pbi)
         fclose(z);
     }
 
-
     {
         /* read coef probability tree */
-
         for (i = 0; i < BLOCK_TYPES; i++)
             for (j = 0; j < COEF_BANDS; j++)
                 for (k = 0; k < PREV_COEF_CONTEXTS; k++)
@@ -1021,7 +1066,6 @@ int vp8_decode_frame(VP8D_COMP *pbi)
         }
     }
 
-
     stop_token_decoder(pbi);
 
     /* Collect information about decoder corruption. */
diff --git a/vp8/decoder/onyxd_if.c b/vp8/decoder/onyxd_if.c
index 9de5ce2c4172e50a722fa11f0a837004d138d3d2..5f81ee6386afb15f6d04e878ebbfe45567d24c22 100644
--- a/vp8/decoder/onyxd_if.c
+++ b/vp8/decoder/onyxd_if.c
@@ -109,6 +109,8 @@ VP8D_PTR vp8dx_create_decompressor(VP8D_CONFIG *oxcf)
     pbi->ec_enabled = 0;
 #endif
 
+    pbi->input_partition = oxcf->input_partition;
+
     return (VP8D_PTR) pbi;
 }
 
@@ -312,68 +314,91 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
 
     pbi->common.error.error_code = VPX_CODEC_OK;
 
-    if (size == 0)
+    if (pbi->input_partition && !(source == NULL && size == 0))
     {
-       /* This is used to signal that we are missing frames.
-        * We do not know if the missing frame(s) was supposed to update
-        * any of the reference buffers, but we act conservative and
-        * mark only the last buffer as corrupted.
-        */
-        cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
-
-        /* If error concealment is disabled we won't signal missing frames to
-         * the decoder.
+        /* Store a pointer to this partition and return. We haven't
+         * received the complete frame yet, so we will wait with decoding.
          */
-        if (!pbi->ec_enabled)
+        pbi->partitions[pbi->num_partitions] = source;
+        pbi->partition_sizes[pbi->num_partitions] = size;
+        pbi->source_sz += size;
+        pbi->num_partitions++;
+        if (pbi->num_partitions > (1<<pbi->common.multi_token_partition) + 1)
+            pbi->common.multi_token_partition++;
+        if (pbi->common.multi_token_partition > EIGHT_PARTITION)
         {
-            /* Signal that we have no frame to show. */
-            cm->show_frame = 0;
-
-            /* Nothing more to do. */
-            return 0;
+            pbi->common.error.error_code = VPX_CODEC_UNSUP_BITSTREAM;
+            pbi->common.error.setjmp = 0;
+            return -1;
         }
+        return 0;
     }
+    else
+    {
+        if (!pbi->input_partition)
+        {
+            pbi->Source = source;
+            pbi->source_sz = size;
+        }
 
+        if (pbi->source_sz == 0)
+        {
+           /* This is used to signal that we are missing frames.
+            * We do not know if the missing frame(s) was supposed to update
+            * any of the reference buffers, but we act conservative and
+            * mark only the last buffer as corrupted.
+            */
+            cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
+
+            /* If error concealment is disabled we won't signal missing frames to
+             * the decoder.
+             */
+            if (!pbi->ec_enabled)
+            {
+                /* Signal that we have no frame to show. */
+                cm->show_frame = 0;
+
+                /* Nothing more to do. */
+                return 0;
+            }
+        }
 
 #if HAVE_ARMV7
 #if CONFIG_RUNTIME_CPU_DETECT
-    if (cm->rtcd.flags & HAS_NEON)
+        if (cm->rtcd.flags & HAS_NEON)
 #endif
-    {
-        vp8_push_neon(dx_store_reg);
-    }
+        {
+            vp8_push_neon(dx_store_reg);
+        }
 #endif
 
-    cm->new_fb_idx = get_free_fb (cm);
+        cm->new_fb_idx = get_free_fb (cm);
 
-    if (setjmp(pbi->common.error.jmp))
-    {
+        if (setjmp(pbi->common.error.jmp))
+        {
 #if HAVE_ARMV7
 #if CONFIG_RUNTIME_CPU_DETECT
-        if (cm->rtcd.flags & HAS_NEON)
+            if (cm->rtcd.flags & HAS_NEON)
 #endif
-        {
-            vp8_pop_neon(dx_store_reg);
-        }
+            {
+                vp8_pop_neon(dx_store_reg);
+            }
 #endif
-        pbi->common.error.setjmp = 0;
-
-       /* We do not know if the missing frame(s) was supposed to update
-        * any of the reference buffers, but we act conservative and
-        * mark only the last buffer as corrupted.
-        */
-        cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
+            pbi->common.error.setjmp = 0;
 
-        if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
-          cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
-        return -1;
-    }
+           /* We do not know if the missing frame(s) was supposed to update
+            * any of the reference buffers, but we act conservative and
+            * mark only the last buffer as corrupted.
+            */
+            cm->yv12_fb[cm->lst_fb_idx].corrupted = 1;
 
-    pbi->common.error.setjmp = 1;
+            if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
+              cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
+            return -1;
+        }
 
-    /*cm->current_video_frame++;*/
-    pbi->Source = source;
-    pbi->source_sz = size;
+        pbi->common.error.setjmp = 1;
+    }
 
     retcode = vp8_decode_frame(pbi);
 
@@ -473,6 +498,10 @@ int vp8dx_receive_compressed_data(VP8D_PTR ptr, unsigned long size, const unsign
 
     pbi->ready_for_new_data = 0;
     pbi->last_time_stamp = time_stamp;
+    pbi->num_partitions = 0;
+    if (pbi->input_partition)
+        pbi->common.multi_token_partition = 0;
+    pbi->source_sz = 0;
 
 #if 0
     {
diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h
index ea6de3dda30dc472efbf0985a3b2b33ee2d5f59b..be6ffe6bef3181fcd44aef5b5cc2f37c27805e0f 100644
--- a/vp8/decoder/onyxd_int.h
+++ b/vp8/decoder/onyxd_int.h
@@ -83,6 +83,9 @@ typedef struct VP8Decompressor
 
     const unsigned char *Source;
     unsigned int   source_sz;
+    const unsigned char *partitions[MAX_PARTITIONS];
+    unsigned int   partition_sizes[MAX_PARTITIONS];
+    unsigned int   num_partitions;
 
 #if CONFIG_MULTITHREAD
     /* variable for threading */
@@ -137,6 +140,7 @@ typedef struct VP8Decompressor
     unsigned int mvs_corrupt_from_mb;
 #endif
     int ec_enabled;
+    int input_partition;
 
 } VP8D_COMP;
 
diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c
index 9280b618078811905196d4f02e2e815010dd7942..ac298126314e52a38e52f620048be6fb5683bdb1 100644
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -377,6 +377,7 @@ static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data,
     unsigned int shift;
     vp8_writer *w = &cpi->bc2;
     *size = 3 * (num_part - 1);
+    cpi->partition_sz[0] += *size;
     ptr = cx_data + (*size);
 
     for (i = 0; i < num_part; i++)
@@ -573,6 +574,9 @@ static void pack_tokens_into_partitions_c(VP8_COMP *cpi, unsigned char *cx_data,
         vp8_stop_encode(w);
         *size +=   w->pos;
 
+        /* The first partition size is set earlier */
+        cpi->partition_sz[i + 1] = w->pos;
+
         if (i < (num_part - 1))
         {
             write_partition_size(cx_data, w->pos);
@@ -1840,6 +1844,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
     }
 
     *size = VP8_HEADER_SIZE + extra_bytes_packed + cpi->bc.pos;
+    cpi->partition_sz[0] = *size;
 
     if (pc->multi_token_partition != ONE_PARTITION)
     {
@@ -1865,6 +1870,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
         vp8_stop_encode(&cpi->bc2);
 
         *size += cpi->bc2.pos;
+        cpi->partition_sz[1] = cpi->bc2.pos;
     }
 }
 
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h
index 3ca61a7cd71f6a48ade749bfe54e3680f962681f..d94436bd8dee34f9356a77cd10111ce66c7323ab 100644
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -501,6 +501,7 @@ typedef struct VP8_COMP
 #endif
 
     TOKENLIST *tplist;
+    unsigned int partition_sz[MAX_PARTITIONS];
     // end of multithread data
 
 
@@ -604,6 +605,8 @@ typedef struct VP8_COMP
     unsigned char *gf_active_flags;
     int gf_active_count;
 
+    int output_partition;
+
     //Store last frame's MV info for next frame MV prediction
     int_mv *lfmv;
     int *lf_ref_frame_sign_bias;
diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c
index db60bfe4fe1f94d797db26081e37c24d25d62bfb..5e1278a4c647042fdc91f34a46c7be3804b79990 100644
--- a/vp8/vp8_cx_iface.c
+++ b/vp8/vp8_cx_iface.c
@@ -731,6 +731,9 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
         if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
             ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1;
 
+        if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION)
+            ((VP8_COMP *)ctx->cpi)->output_partition = 1;
+
         /* Convert API flags to internal codec lib flags */
         lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
 
@@ -770,8 +773,6 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
                 round = 1000000 * ctx->cfg.g_timebase.num / 2 - 1;
                 delta = (dst_end_time_stamp - dst_time_stamp);
                 pkt.kind = VPX_CODEC_CX_FRAME_PKT;
-                pkt.data.frame.buf = cx_data;
-                pkt.data.frame.sz  = size;
                 pkt.data.frame.pts =
                     (dst_time_stamp * ctx->cfg.g_timebase.den + round)
                     / ctx->cfg.g_timebase.num / 10000000;
@@ -797,11 +798,35 @@ static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
                     pkt.data.frame.duration = 0;
                 }
 
-                vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+                if (cpi->output_partition)
+                {
+                    int i;
+                    const int num_partitions =
+                            (1 << cpi->common.multi_token_partition) + 1;
+                    for (i = 0; i < num_partitions; ++i)
+                    {
+                        pkt.data.frame.buf = cx_data;
+                        pkt.data.frame.sz = cpi->partition_sz[i];
+                        pkt.data.frame.partition_id = i;
+                        /* don't set the fragment bit for the last partition */
+                        if (i < num_partitions - 1)
+                            pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT;
+                        vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+                        cx_data += cpi->partition_sz[i];
+                        cx_data_sz -= cpi->partition_sz[i];
+                    }
+                }
+                else
+                {
+                    pkt.data.frame.buf = cx_data;
+                    pkt.data.frame.sz  = size;
+                    pkt.data.frame.partition_id = -1;
+                    vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
+                    cx_data += size;
+                    cx_data_sz -= size;
+                }
 
                 //printf("timestamp: %lld, duration: %d\n", pkt->data.frame.pts, pkt->data.frame.duration);
-                cx_data += size;
-                cx_data_sz -= size;
             }
         }
     }
@@ -1121,7 +1146,8 @@ CODEC_INTERFACE(vpx_codec_vp8_cx) =
 {
     "WebM Project VP8 Encoder" VERSION_STRING,
     VPX_CODEC_INTERNAL_ABI_VERSION,
-    VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR,
+    VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR |
+    VPX_CODEC_CAP_OUTPUT_PARTITION,
     /* vpx_codec_caps_t          caps; */
     vp8e_init,          /* vpx_codec_init_fn_t       init; */
     vp8e_destroy,       /* vpx_codec_destroy_fn_t    destroy; */
diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c
index d74dc87bcdc52c685a1832d648e59ad19115e6ce..58dc486dea8430e7538adda09542ffbffbc75ab2 100644
--- a/vp8/vp8_dx_iface.c
+++ b/vp8/vp8_dx_iface.c
@@ -368,6 +368,8 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t  *ctx,
             oxcf.max_threads = ctx->cfg.threads;
             oxcf.error_concealment =
                     (ctx->base.init_flags & VPX_CODEC_USE_ERROR_CONCEALMENT);
+            oxcf.input_partition =
+                    (ctx->base.init_flags & VPX_CODEC_USE_INPUT_PARTITION);
 
             optr = vp8dx_create_decompressor(&oxcf);
 
@@ -721,7 +723,8 @@ CODEC_INTERFACE(vpx_codec_vp8_dx) =
 {
     "WebM Project VP8 Decoder" VERSION_STRING,
     VPX_CODEC_INTERNAL_ABI_VERSION,
-    VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT,
+    VPX_CODEC_CAP_DECODER | VP8_CAP_POSTPROC | VP8_CAP_ERROR_CONCEALMENT |
+    VPX_CODEC_CAP_INPUT_PARTITION,
     /* vpx_codec_caps_t          caps; */
     vp8_init,         /* vpx_codec_init_fn_t       init; */
     vp8_destroy,      /* vpx_codec_destroy_fn_t    destroy; */
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index d168d5cfd5ca93cc09ea67175323f8651e776c3e..71153d55f5e820db42c92f308b1a6094e0d3f34f 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -163,6 +163,13 @@ extern "C" {
                 unsigned long            duration; /**< duration to show frame
                                                     (in timebase units) */
                 vpx_codec_frame_flags_t  flags;    /**< flags for this frame */
+                int                      partition_id; /**< the partition id
+                                              defines the decoding order
+                                              of the partitions. Only
+                                              applicable when "output partition"
+                                              mode is enabled. First partition
+                                              has id 0.*/
+
             } frame;  /**< data for compressed frame packet */
             struct vpx_fixed_buf twopass_stats;  /**< data for two-pass packet */
             struct vpx_psnr_pkt