Merge changes Ifb450710,I61c4a132

* changes:
  Eliminated reconintra_mt.c
  Eliminated vp8mt_build_intra_predictors_mbuv_s
diff --git a/vp8/common/idctllm_test.cc b/vp8/common/idctllm_test.cc
new file mode 100755
index 0000000..0f6ebe7
--- /dev/null
+++ b/vp8/common/idctllm_test.cc
@@ -0,0 +1,31 @@
+/*
+ *  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.
+ */
+
+
+ extern "C" {
+    void vp8_short_idct4x4llm_c(short *input, unsigned char *pred_ptr,
+                            int pred_stride, unsigned char *dst_ptr,
+                            int dst_stride);
+}
+
+#include "vpx_config.h"
+#include "idctllm_test.h"
+namespace
+{
+
+INSTANTIATE_TEST_CASE_P(C, IDCTTest,
+                        ::testing::Values(vp8_short_idct4x4llm_c));
+
+} // namespace
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/vp8/common/idctllm_test.h b/vp8/common/idctllm_test.h
new file mode 100755
index 0000000..a6a694b
--- /dev/null
+++ b/vp8/common/idctllm_test.h
@@ -0,0 +1,113 @@
+/*
+ *  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 "third_party/googletest/src/include/gtest/gtest.h"
+typedef void (*idct_fn_t)(short *input, unsigned char *pred_ptr,
+                            int pred_stride, unsigned char *dst_ptr,
+                            int dst_stride);
+namespace {
+class IDCTTest : public ::testing::TestWithParam<idct_fn_t>
+{
+  protected:
+    virtual void SetUp()
+    {
+        int i;
+
+        UUT = GetParam();
+        memset(input, 0, sizeof(input));
+        /* Set up guard blocks */
+        for(i=0; i<256; i++)
+            output[i] = ((i&0xF)<4&&(i<64))?0:-1;
+    }
+
+    idct_fn_t UUT;
+    short input[16];
+    unsigned char output[256];
+    unsigned char predict[256];
+};
+
+TEST_P(IDCTTest, TestGuardBlocks)
+{
+    int i;
+
+    for(i=0; i<256; i++)
+        if((i&0xF) < 4 && i<64)
+            EXPECT_EQ(0, output[i]) << i;
+        else
+            EXPECT_EQ(255, output[i]);
+}
+
+TEST_P(IDCTTest, TestAllZeros)
+{
+    int i;
+
+    UUT(input, output, 16, output, 16);
+
+    for(i=0; i<256; i++)
+        if((i&0xF) < 4 && i<64)
+            EXPECT_EQ(0, output[i]) << "i==" << i;
+        else
+            EXPECT_EQ(255, output[i]) << "i==" << i;
+}
+
+TEST_P(IDCTTest, TestAllOnes)
+{
+    int i;
+
+    input[0] = 4;
+    UUT(input, output, 16, output, 16);
+
+    for(i=0; i<256; i++)
+        if((i&0xF) < 4 && i<64)
+            EXPECT_EQ(1, output[i]) << "i==" << i;
+        else
+            EXPECT_EQ(255, output[i]) << "i==" << i;
+}
+
+TEST_P(IDCTTest, TestAddOne)
+{
+    int i;
+
+    for(i=0; i<256; i++)
+        predict[i] = i;
+
+    input[0] = 4;
+    UUT(input, predict, 16, output, 16);
+
+    for(i=0; i<256; i++)
+        if((i&0xF) < 4 && i<64)
+            EXPECT_EQ(i+1, output[i]) << "i==" << i;
+        else
+            EXPECT_EQ(255, output[i]) << "i==" << i;
+}
+
+TEST_P(IDCTTest, TestWithData)
+{
+    int i;
+
+    for(i=0; i<16; i++)
+        input[i] = i;
+
+    UUT(input, output, 16, output, 16);
+
+    for(i=0; i<256; i++)
+        if((i&0xF) > 3 || i>63)
+            EXPECT_EQ(255, output[i]) << "i==" << i;
+        else if(i == 0)
+            EXPECT_EQ(11, output[i]) << "i==" << i;
+        else if(i == 34)
+            EXPECT_EQ(1, output[i]) << "i==" << i;
+        else if(i == 2 || i == 17 || i == 32)
+            EXPECT_EQ(3, output[i]) << "i==" << i;
+        else
+            EXPECT_EQ(0, output[i]) << "i==" << i;
+}
+}
diff --git a/vp8/common/x86/idctllm_mmx_test.cc b/vp8/common/x86/idctllm_mmx_test.cc
new file mode 100755
index 0000000..8c11533
--- /dev/null
+++ b/vp8/common/x86/idctllm_mmx_test.cc
@@ -0,0 +1,31 @@
+/*
+ *  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.
+ */
+
+
+ extern "C" {
+    void vp8_short_idct4x4llm_mmx(short *input, unsigned char *pred_ptr,
+                            int pred_stride, unsigned char *dst_ptr,
+                            int dst_stride);
+}
+
+#include "vp8/common/idctllm_test.h"
+
+namespace
+{
+
+INSTANTIATE_TEST_CASE_P(MMX, IDCTTest,
+                        ::testing::Values(vp8_short_idct4x4llm_mmx));
+
+} // namespace
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c
index 670c36f..c368a4c 100644
--- a/vp8/decoder/decodframe.c
+++ b/vp8/decoder/decodframe.c
@@ -849,6 +849,12 @@
             }
         }
     }
+    else
+    {
+        /* No segmentation updates on this frame */
+        xd->update_mb_segmentation_map = 0;
+        xd->update_mb_segmentation_data = 0;
+    }
 
     /* Read the loop filter level and type */
     pc->filter_type = (LOOPFILTERTYPE) vp8_read_bit(bc);
diff --git a/vp8/decoder/onyxd_int.h b/vp8/decoder/onyxd_int.h
index 989f68b..97cf0dc 100644
--- a/vp8/decoder/onyxd_int.h
+++ b/vp8/decoder/onyxd_int.h
@@ -32,8 +32,6 @@
 {
     MACROBLOCKD  mbd;
     int mb_row;
-    int current_mb_col;
-    short *coef_ptr;
 } MB_ROW_DEC;
 
 typedef struct
diff --git a/vp8/decoder/threading.c b/vp8/decoder/threading.c
index 4773a08..36db8fb 100644
--- a/vp8/decoder/threading.c
+++ b/vp8/decoder/threading.c
@@ -305,6 +305,271 @@
                      xd->dst.uv_stride, xd->eobs+16);
 }
 
+typedef void (*init_current_bc_fn_t)(VP8D_COMP *pbi, MACROBLOCKD *xd,
+    int start_mb_row, int mb_row, int num_part);
+
+static void init_current_bc(VP8D_COMP *pbi, MACROBLOCKD *xd, int start_mb_row,
+                     int mb_row, int num_part)
+{
+    (void) start_mb_row;
+
+    xd->current_bc = &pbi->mbc[mb_row%num_part];
+}
+
+static void init_current_bc_threads(VP8D_COMP *pbi, MACROBLOCKD *xd,
+                     int start_mb_row, int mb_row, int num_part)
+{
+    (void) xd;
+    pbi->mb_row_di[start_mb_row - 1].mb_row = mb_row;
+    pbi->mb_row_di[start_mb_row - 1].mbd.current_bc =  &pbi->mbc[mb_row%num_part];
+}
+
+
+static void decode_mb_rows(VP8D_COMP *pbi, MACROBLOCKD *xd, int start_mb_row,
+                           init_current_bc_fn_t init_current_bc_fn)
+{
+    volatile int *last_row_current_mb_col = NULL;
+    int mb_row;
+    VP8_COMMON *pc = &pbi->common;
+    int nsync = pbi->sync_range;
+    int num_part = 1 << pbi->common.multi_token_partition;
+
+
+    for (mb_row = start_mb_row; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1))
+    {
+       int i;
+       int recon_yoffset, recon_uvoffset;
+       int mb_col;
+       int ref_fb_idx = pc->lst_fb_idx;
+       int dst_fb_idx = pc->new_fb_idx;
+       int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride;
+       int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride;
+
+       int filter_level;
+       loop_filter_info_n *lfi_n = &pc->lf_info;
+
+       init_current_bc_fn(pbi, xd, start_mb_row, mb_row, num_part);
+
+       if (mb_row > 0)
+           last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1];
+
+       recon_yoffset = mb_row * recon_y_stride * 16;
+       recon_uvoffset = mb_row * recon_uv_stride * 8;
+       /* reset above block coeffs */
+
+       xd->above_context = pc->above_context;
+       vpx_memset(xd->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES));
+       xd->up_available = (mb_row != 0);
+
+       xd->mb_to_top_edge = -((mb_row * 16)) << 3;
+       xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3;
+
+       for (mb_col = 0; mb_col < pc->mb_cols; mb_col++)
+       {
+           if ( mb_row > 0 && (mb_col & (nsync-1)) == 0)
+           {
+               while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1)
+               {
+                   x86_pause_hint();
+                   thread_sleep(0);
+               }
+           }
+
+           /* Distance of MB to the various image edges.
+            * These are specified to 8th pel as they are always
+            * compared to values that are in 1/8th pel units.
+            */
+           xd->mb_to_left_edge = -((mb_col * 16) << 3);
+           xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
+
+    #if CONFIG_ERROR_CONCEALMENT
+           {
+               int corrupt_residual =
+                           (!pbi->independent_partitions &&
+                           pbi->frame_corrupt_residual) ||
+                           vp8dx_bool_error(xd->current_bc);
+               if (pbi->ec_active &&
+                   (xd->mode_info_context->mbmi.ref_frame ==
+                                                    INTRA_FRAME) &&
+                   corrupt_residual)
+               {
+                   /* We have an intra block with corrupt
+                    * coefficients, better to conceal with an inter
+                    * block.
+                    * Interpolate MVs from neighboring MBs
+                    *
+                    * Note that for the first mb with corrupt
+                    * residual in a frame, we might not discover
+                    * that before decoding the residual. That
+                    * happens after this check, and therefore no
+                    * inter concealment will be done.
+                    */
+                   vp8_interpolate_motion(xd,
+                                          mb_row, mb_col,
+                                          pc->mb_rows, pc->mb_cols,
+                                          pc->mode_info_stride);
+               }
+           }
+    #endif
+
+
+           xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
+           xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
+           xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset;
+
+           xd->left_available = (mb_col != 0);
+
+           /* Select the appropriate reference frame for this MB */
+           if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)
+               ref_fb_idx = pc->lst_fb_idx;
+           else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME)
+               ref_fb_idx = pc->gld_fb_idx;
+           else
+               ref_fb_idx = pc->alt_fb_idx;
+
+           xd->pre.y_buffer = pc->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset;
+           xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
+           xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
+
+           if (xd->mode_info_context->mbmi.ref_frame !=
+                   INTRA_FRAME)
+           {
+               /* propagate errors from reference frames */
+               xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
+           }
+
+           decode_macroblock(pbi, xd, mb_row, mb_col);
+
+           /* check if the boolean decoder has suffered an error */
+           xd->corrupted |= vp8dx_bool_error(xd->current_bc);
+
+           if (pbi->common.filter_level)
+           {
+               int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
+                               xd->mode_info_context->mbmi.mode != SPLITMV &&
+                               xd->mode_info_context->mbmi.mb_skip_coeff);
+
+               const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode];
+               const int seg = xd->mode_info_context->mbmi.segment_id;
+               const int ref_frame = xd->mode_info_context->mbmi.ref_frame;
+
+               filter_level = lfi_n->lvl[seg][ref_frame][mode_index];
+
+               if( mb_row != pc->mb_rows-1 )
+               {
+                   /* Save decoded MB last row data for next-row decoding */
+                   vpx_memcpy((pbi->mt_yabove_row[mb_row + 1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16);
+                   vpx_memcpy((pbi->mt_uabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8);
+                   vpx_memcpy((pbi->mt_vabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8);
+               }
+
+               /* save left_col for next MB decoding */
+               if(mb_col != pc->mb_cols-1)
+               {
+                   MODE_INFO *next = xd->mode_info_context +1;
+
+                   if (next->mbmi.ref_frame == INTRA_FRAME)
+                   {
+                       for (i = 0; i < 16; i++)
+                           pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15];
+                       for (i = 0; i < 8; i++)
+                       {
+                           pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7];
+                           pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7];
+                       }
+                   }
+               }
+
+               /* loopfilter on this macroblock. */
+               if (filter_level)
+               {
+                   if(pc->filter_type == NORMAL_LOOPFILTER)
+                   {
+                       loop_filter_info lfi;
+                       FRAME_TYPE frame_type = pc->frame_type;
+                       const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level];
+                       lfi.mblim = lfi_n->mblim[filter_level];
+                       lfi.blim = lfi_n->blim[filter_level];
+                       lfi.lim = lfi_n->lim[filter_level];
+                       lfi.hev_thr = lfi_n->hev_thr[hev_index];
+
+                       if (mb_col > 0)
+                           vp8_loop_filter_mbv
+                           (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
+
+                       if (!skip_lf)
+                           vp8_loop_filter_bv
+                           (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
+
+                       /* don't apply across umv border */
+                       if (mb_row > 0)
+                           vp8_loop_filter_mbh
+                           (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
+
+                       if (!skip_lf)
+                           vp8_loop_filter_bh
+                           (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer,  recon_y_stride, recon_uv_stride, &lfi);
+                   }
+                   else
+                   {
+                       if (mb_col > 0)
+                           vp8_loop_filter_simple_mbv
+                           (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
+
+                       if (!skip_lf)
+                           vp8_loop_filter_simple_bv
+                           (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
+
+                       /* don't apply across umv border */
+                       if (mb_row > 0)
+                           vp8_loop_filter_simple_mbh
+                           (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
+
+                       if (!skip_lf)
+                           vp8_loop_filter_simple_bh
+                           (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
+                   }
+               }
+
+           }
+
+           recon_yoffset += 16;
+           recon_uvoffset += 8;
+
+           ++xd->mode_info_context;  /* next mb */
+
+           xd->above_context++;
+
+           /*pbi->mb_row_di[ithread].current_mb_col = mb_col;*/
+           pbi->mt_current_mb_col[mb_row] = mb_col;
+       }
+
+       /* adjust to the next row of mbs */
+       if (pbi->common.filter_level)
+       {
+           if(mb_row != pc->mb_rows-1)
+           {
+               int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS;
+               int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1);
+
+               for (i = 0; i < 4; i++)
+               {
+                   pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1];
+                   pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1];
+                   pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1];
+               }
+           }
+       } else
+           vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8);
+
+       ++xd->mode_info_context;      /* skip prediction column */
+
+       /* since we have multithread */
+       xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count;
+    }
+}
+
+
 static THREAD_FUNCTION thread_decoding_proc(void *p_data)
 {
     int ithread = ((DECODETHREAD_DATA *)p_data)->ithread;
@@ -324,251 +589,18 @@
                 break;
             else
             {
-                VP8_COMMON *pc = &pbi->common;
                 MACROBLOCKD *xd = &mbrd->mbd;
 
-                int mb_row;
-                int num_part = 1 << pbi->common.multi_token_partition;
-                volatile int *last_row_current_mb_col;
-                int nsync = pbi->sync_range;
+                xd->left_context = &mb_row_left_context;
 
-                for (mb_row = ithread+1; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1))
-                {
-                    int i;
-                    int recon_yoffset, recon_uvoffset;
-                    int mb_col;
-                    int ref_fb_idx = pc->lst_fb_idx;
-                    int dst_fb_idx = pc->new_fb_idx;
-                    int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride;
-                    int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride;
-
-                    int filter_level;
-                    loop_filter_info_n *lfi_n = &pc->lf_info;
-
-                    pbi->mb_row_di[ithread].mb_row = mb_row;
-                    pbi->mb_row_di[ithread].mbd.current_bc =  &pbi->mbc[mb_row%num_part];
-
-                    last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1];
-
-                    recon_yoffset = mb_row * recon_y_stride * 16;
-                    recon_uvoffset = mb_row * recon_uv_stride * 8;
-                    /* reset above block coeffs */
-
-                    xd->above_context = pc->above_context;
-                    xd->left_context = &mb_row_left_context;
-                    vpx_memset(&mb_row_left_context, 0, sizeof(mb_row_left_context));
-                    xd->up_available = (mb_row != 0);
-
-                    xd->mb_to_top_edge = -((mb_row * 16)) << 3;
-                    xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3;
-
-                    for (mb_col = 0; mb_col < pc->mb_cols; mb_col++)
-                    {
-                        if ((mb_col & (nsync-1)) == 0)
-                        {
-                            while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1)
-                            {
-                                x86_pause_hint();
-                                thread_sleep(0);
-                            }
-                        }
-
-                        /* Distance of MB to the various image edges.
-                         * These are specified to 8th pel as they are always
-                         * compared to values that are in 1/8th pel units.
-                         */
-                        xd->mb_to_left_edge = -((mb_col * 16) << 3);
-                        xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
-
-#if CONFIG_ERROR_CONCEALMENT
-                        {
-                            int corrupt_residual =
-                                        (!pbi->independent_partitions &&
-                                        pbi->frame_corrupt_residual) ||
-                                        vp8dx_bool_error(xd->current_bc);
-                            if (pbi->ec_active &&
-                                (xd->mode_info_context->mbmi.ref_frame ==
-                                                                 INTRA_FRAME) &&
-                                corrupt_residual)
-                            {
-                                /* We have an intra block with corrupt
-                                 * coefficients, better to conceal with an inter
-                                 * block.
-                                 * Interpolate MVs from neighboring MBs
-                                 *
-                                 * Note that for the first mb with corrupt
-                                 * residual in a frame, we might not discover
-                                 * that before decoding the residual. That
-                                 * happens after this check, and therefore no
-                                 * inter concealment will be done.
-                                 */
-                                vp8_interpolate_motion(xd,
-                                                       mb_row, mb_col,
-                                                       pc->mb_rows, pc->mb_cols,
-                                                       pc->mode_info_stride);
-                            }
-                        }
-#endif
-
-
-                        xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
-                        xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
-                        xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset;
-
-                        xd->left_available = (mb_col != 0);
-
-                        /* Select the appropriate reference frame for this MB */
-                        if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)
-                            ref_fb_idx = pc->lst_fb_idx;
-                        else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME)
-                            ref_fb_idx = pc->gld_fb_idx;
-                        else
-                            ref_fb_idx = pc->alt_fb_idx;
-
-                        xd->pre.y_buffer = pc->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset;
-                        xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
-                        xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
-
-                        if (xd->mode_info_context->mbmi.ref_frame !=
-                                INTRA_FRAME)
-                        {
-                            /* propagate errors from reference frames */
-                            xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
-                        }
-
-                        decode_macroblock(pbi, xd, mb_row, mb_col);
-
-                        /* check if the boolean decoder has suffered an error */
-                        xd->corrupted |= vp8dx_bool_error(xd->current_bc);
-
-                        if (pbi->common.filter_level)
-                        {
-                            int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
-                                            xd->mode_info_context->mbmi.mode != SPLITMV &&
-                                            xd->mode_info_context->mbmi.mb_skip_coeff);
-
-                            const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode];
-                            const int seg = xd->mode_info_context->mbmi.segment_id;
-                            const int ref_frame = xd->mode_info_context->mbmi.ref_frame;
-
-                            filter_level = lfi_n->lvl[seg][ref_frame][mode_index];
-
-                            if( mb_row != pc->mb_rows-1 )
-                            {
-                                /* Save decoded MB last row data for next-row decoding */
-                                vpx_memcpy((pbi->mt_yabove_row[mb_row + 1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16);
-                                vpx_memcpy((pbi->mt_uabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8);
-                                vpx_memcpy((pbi->mt_vabove_row[mb_row + 1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8);
-                            }
-
-                            /* save left_col for next MB decoding */
-                            if(mb_col != pc->mb_cols-1)
-                            {
-                                MODE_INFO *next = xd->mode_info_context +1;
-
-                                if (next->mbmi.ref_frame == INTRA_FRAME)
-                                {
-                                    for (i = 0; i < 16; i++)
-                                        pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15];
-                                    for (i = 0; i < 8; i++)
-                                    {
-                                        pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7];
-                                        pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7];
-                                    }
-                                }
-                            }
-
-                            /* loopfilter on this macroblock. */
-                            if (filter_level)
-                            {
-                                if(pc->filter_type == NORMAL_LOOPFILTER)
-                                {
-                                    loop_filter_info lfi;
-                                    FRAME_TYPE frame_type = pc->frame_type;
-                                    const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level];
-                                    lfi.mblim = lfi_n->mblim[filter_level];
-                                    lfi.blim = lfi_n->blim[filter_level];
-                                    lfi.lim = lfi_n->lim[filter_level];
-                                    lfi.hev_thr = lfi_n->hev_thr[hev_index];
-
-                                    if (mb_col > 0)
-                                        vp8_loop_filter_mbv
-                                        (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                                    if (!skip_lf)
-                                        vp8_loop_filter_bv
-                                        (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                                    /* don't apply across umv border */
-                                    if (mb_row > 0)
-                                        vp8_loop_filter_mbh
-                                        (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                                    if (!skip_lf)
-                                        vp8_loop_filter_bh
-                                        (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer,  recon_y_stride, recon_uv_stride, &lfi);
-                                }
-                                else
-                                {
-                                    if (mb_col > 0)
-                                        vp8_loop_filter_simple_mbv
-                                        (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
-
-                                    if (!skip_lf)
-                                        vp8_loop_filter_simple_bv
-                                        (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
-
-                                    /* don't apply across umv border */
-                                    if (mb_row > 0)
-                                        vp8_loop_filter_simple_mbh
-                                        (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
-
-                                    if (!skip_lf)
-                                        vp8_loop_filter_simple_bh
-                                        (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
-                                }
-                            }
-
-                        }
-
-                        recon_yoffset += 16;
-                        recon_uvoffset += 8;
-
-                        ++xd->mode_info_context;  /* next mb */
-
-                        xd->above_context++;
-
-                        /*pbi->mb_row_di[ithread].current_mb_col = mb_col;*/
-                        pbi->mt_current_mb_col[mb_row] = mb_col;
-                    }
-
-                    /* adjust to the next row of mbs */
-                    if (pbi->common.filter_level)
-                    {
-                        if(mb_row != pc->mb_rows-1)
-                        {
-                            int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS;
-                            int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1);
-
-                            for (i = 0; i < 4; i++)
-                            {
-                                pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1];
-                                pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1];
-                                pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1];
-                            }
-                        }
-                    } else
-                        vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8);
-
-                    ++xd->mode_info_context;      /* skip prediction column */
-
-                    /* since we have multithread */
-                    xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count;
-                }
+                decode_mb_rows(pbi, xd, ithread+1, init_current_bc_threads);
             }
         }
+
         /*  add this to each frame */
-        if ((mbrd->mb_row == pbi->common.mb_rows-1) || ((mbrd->mb_row == pbi->common.mb_rows-2) && (pbi->common.mb_rows % (pbi->decoding_thread_count+1))==1))
+        if ((mbrd->mb_row == pbi->common.mb_rows-1) ||
+            ((mbrd->mb_row == pbi->common.mb_rows-2) &&
+                (pbi->common.mb_rows % (pbi->decoding_thread_count+1))==1))
         {
             /*SetEvent(pbi->h_event_end_decoding);*/
             sem_post(&pbi->h_event_end_decoding);
@@ -795,16 +827,10 @@
 
 void vp8mt_decode_mb_rows( VP8D_COMP *pbi, MACROBLOCKD *xd)
 {
-    int mb_row;
     VP8_COMMON *pc = &pbi->common;
-
-    int num_part = 1 << pbi->common.multi_token_partition;
     int i;
-    volatile int *last_row_current_mb_col = NULL;
-    int nsync = pbi->sync_range;
 
     int filter_level = pc->filter_level;
-    loop_filter_info_n *lfi_n = &pc->lf_info;
 
     if (filter_level)
     {
@@ -837,229 +863,7 @@
     for (i = 0; i < pbi->decoding_thread_count; i++)
         sem_post(&pbi->h_event_start_decoding[i]);
 
-    for (mb_row = 0; mb_row < pc->mb_rows; mb_row += (pbi->decoding_thread_count + 1))
-    {
-        xd->current_bc = &pbi->mbc[mb_row%num_part];
-
-        /* vp8_decode_mb_row(pbi, pc, mb_row, xd); */
-        {
-            int i;
-            int recon_yoffset, recon_uvoffset;
-            int mb_col;
-            int ref_fb_idx = pc->lst_fb_idx;
-            int dst_fb_idx = pc->new_fb_idx;
-            int recon_y_stride = pc->yv12_fb[ref_fb_idx].y_stride;
-            int recon_uv_stride = pc->yv12_fb[ref_fb_idx].uv_stride;
-
-           /* volatile int *last_row_current_mb_col = NULL; */
-            if (mb_row > 0)
-                last_row_current_mb_col = &pbi->mt_current_mb_col[mb_row -1];
-
-            vpx_memset(&pc->left_context, 0, sizeof(pc->left_context));
-            recon_yoffset = mb_row * recon_y_stride * 16;
-            recon_uvoffset = mb_row * recon_uv_stride * 8;
-            /* reset above block coeffs */
-
-            xd->above_context = pc->above_context;
-            xd->up_available = (mb_row != 0);
-
-            xd->mb_to_top_edge = -((mb_row * 16)) << 3;
-            xd->mb_to_bottom_edge = ((pc->mb_rows - 1 - mb_row) * 16) << 3;
-
-            for (mb_col = 0; mb_col < pc->mb_cols; mb_col++)
-            {
-                if ( mb_row > 0 && (mb_col & (nsync-1)) == 0){
-                    while (mb_col > (*last_row_current_mb_col - nsync) && *last_row_current_mb_col != pc->mb_cols - 1)
-                    {
-                        x86_pause_hint();
-                        thread_sleep(0);
-                    }
-                }
-
-                /* Distance of MB to the various image edges.
-                 * These are specified to 8th pel as they are always compared to
-                 * values that are in 1/8th pel units.
-                 */
-                xd->mb_to_left_edge = -((mb_col * 16) << 3);
-                xd->mb_to_right_edge = ((pc->mb_cols - 1 - mb_col) * 16) << 3;
-
-#if CONFIG_ERROR_CONCEALMENT
-                {
-                    int corrupt_residual = (!pbi->independent_partitions &&
-                                            pbi->frame_corrupt_residual) ||
-                                            vp8dx_bool_error(xd->current_bc);
-                    if (pbi->ec_active &&
-                        (xd->mode_info_context->mbmi.ref_frame == INTRA_FRAME) &&
-                        corrupt_residual)
-                    {
-                        /* We have an intra block with corrupt coefficients,
-                         * better to conceal with an inter block. Interpolate
-                         * MVs from neighboring MBs
-                         *
-                         * Note that for the first mb with corrupt residual in a
-                         * frame, we might not discover that before decoding the
-                         * residual. That happens after this check, and
-                         * therefore no inter concealment will be done.
-                         */
-                        vp8_interpolate_motion(xd,
-                                               mb_row, mb_col,
-                                               pc->mb_rows, pc->mb_cols,
-                                               pc->mode_info_stride);
-                    }
-                }
-#endif
-
-
-                xd->dst.y_buffer = pc->yv12_fb[dst_fb_idx].y_buffer + recon_yoffset;
-                xd->dst.u_buffer = pc->yv12_fb[dst_fb_idx].u_buffer + recon_uvoffset;
-                xd->dst.v_buffer = pc->yv12_fb[dst_fb_idx].v_buffer + recon_uvoffset;
-
-                xd->left_available = (mb_col != 0);
-
-                /* Select the appropriate reference frame for this MB */
-                if (xd->mode_info_context->mbmi.ref_frame == LAST_FRAME)
-                    ref_fb_idx = pc->lst_fb_idx;
-                else if (xd->mode_info_context->mbmi.ref_frame == GOLDEN_FRAME)
-                    ref_fb_idx = pc->gld_fb_idx;
-                else
-                    ref_fb_idx = pc->alt_fb_idx;
-
-                xd->pre.y_buffer = pc->yv12_fb[ref_fb_idx].y_buffer + recon_yoffset;
-                xd->pre.u_buffer = pc->yv12_fb[ref_fb_idx].u_buffer + recon_uvoffset;
-                xd->pre.v_buffer = pc->yv12_fb[ref_fb_idx].v_buffer + recon_uvoffset;
-
-                if (xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME)
-                {
-                    /* propagate errors from reference frames */
-                    xd->corrupted |= pc->yv12_fb[ref_fb_idx].corrupted;
-                }
-
-                decode_macroblock(pbi, xd, mb_row, mb_col);
-
-                /* check if the boolean decoder has suffered an error */
-                xd->corrupted |= vp8dx_bool_error(xd->current_bc);
-
-                if (pbi->common.filter_level)
-                {
-                    int skip_lf = (xd->mode_info_context->mbmi.mode != B_PRED &&
-                                    xd->mode_info_context->mbmi.mode != SPLITMV &&
-                                    xd->mode_info_context->mbmi.mb_skip_coeff);
-
-                    const int mode_index = lfi_n->mode_lf_lut[xd->mode_info_context->mbmi.mode];
-                    const int seg = xd->mode_info_context->mbmi.segment_id;
-                    const int ref_frame = xd->mode_info_context->mbmi.ref_frame;
-
-                    filter_level = lfi_n->lvl[seg][ref_frame][mode_index];
-
-                    /* Save decoded MB last row data for next-row decoding */
-                    if(mb_row != pc->mb_rows-1)
-                    {
-                        vpx_memcpy((pbi->mt_yabove_row[mb_row +1] + 32 + mb_col*16), (xd->dst.y_buffer + 15 * recon_y_stride), 16);
-                        vpx_memcpy((pbi->mt_uabove_row[mb_row +1] + 16 + mb_col*8), (xd->dst.u_buffer + 7 * recon_uv_stride), 8);
-                        vpx_memcpy((pbi->mt_vabove_row[mb_row +1] + 16 + mb_col*8), (xd->dst.v_buffer + 7 * recon_uv_stride), 8);
-                    }
-
-                    /* save left_col for next MB decoding */
-                    if(mb_col != pc->mb_cols-1)
-                    {
-                        MODE_INFO *next = xd->mode_info_context +1;
-
-                        if (next->mbmi.ref_frame == INTRA_FRAME)
-                        {
-                            for (i = 0; i < 16; i++)
-                                pbi->mt_yleft_col[mb_row][i] = xd->dst.y_buffer [i* recon_y_stride + 15];
-                            for (i = 0; i < 8; i++)
-                            {
-                                pbi->mt_uleft_col[mb_row][i] = xd->dst.u_buffer [i* recon_uv_stride + 7];
-                                pbi->mt_vleft_col[mb_row][i] = xd->dst.v_buffer [i* recon_uv_stride + 7];
-                            }
-                        }
-                    }
-
-                    /* loopfilter on this macroblock. */
-                    if (filter_level)
-                    {
-                        if(pc->filter_type == NORMAL_LOOPFILTER)
-                        {
-                            loop_filter_info lfi;
-                            FRAME_TYPE frame_type = pc->frame_type;
-                            const int hev_index = lfi_n->hev_thr_lut[frame_type][filter_level];
-                            lfi.mblim = lfi_n->mblim[filter_level];
-                            lfi.blim = lfi_n->blim[filter_level];
-                            lfi.lim = lfi_n->lim[filter_level];
-                            lfi.hev_thr = lfi_n->hev_thr[hev_index];
-
-                            if (mb_col > 0)
-                                vp8_loop_filter_mbv
-                                (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                            if (!skip_lf)
-                                vp8_loop_filter_bv
-                                (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                            /* don't apply across umv border */
-                            if (mb_row > 0)
-                                vp8_loop_filter_mbh
-                                (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer, recon_y_stride, recon_uv_stride, &lfi);
-
-                            if (!skip_lf)
-                                vp8_loop_filter_bh
-                                (xd->dst.y_buffer, xd->dst.u_buffer, xd->dst.v_buffer,  recon_y_stride, recon_uv_stride, &lfi);
-                        }
-                        else
-                        {
-                            if (mb_col > 0)
-                                vp8_loop_filter_simple_mbv
-                                (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
-
-                            if (!skip_lf)
-                                vp8_loop_filter_simple_bv
-                                (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
-
-                            /* don't apply across umv border */
-                            if (mb_row > 0)
-                                vp8_loop_filter_simple_mbh
-                                (xd->dst.y_buffer, recon_y_stride, lfi_n->mblim[filter_level]);
-
-                            if (!skip_lf)
-                                vp8_loop_filter_simple_bh
-                                (xd->dst.y_buffer, recon_y_stride, lfi_n->blim[filter_level]);
-                        }
-                    }
-
-                }
-                recon_yoffset += 16;
-                recon_uvoffset += 8;
-
-                ++xd->mode_info_context;  /* next mb */
-
-                xd->above_context++;
-
-                pbi->mt_current_mb_col[mb_row] = mb_col;
-            }
-
-            /* adjust to the next row of mbs */
-            if (pbi->common.filter_level)
-            {
-                if(mb_row != pc->mb_rows-1)
-                {
-                    int lasty = pc->yv12_fb[ref_fb_idx].y_width + VP8BORDERINPIXELS;
-                    int lastuv = (pc->yv12_fb[ref_fb_idx].y_width>>1) + (VP8BORDERINPIXELS>>1);
-
-                    for (i = 0; i < 4; i++)
-                    {
-                        pbi->mt_yabove_row[mb_row +1][lasty + i] = pbi->mt_yabove_row[mb_row +1][lasty -1];
-                        pbi->mt_uabove_row[mb_row +1][lastuv + i] = pbi->mt_uabove_row[mb_row +1][lastuv -1];
-                        pbi->mt_vabove_row[mb_row +1][lastuv + i] = pbi->mt_vabove_row[mb_row +1][lastuv -1];
-                    }
-                }
-            }else
-                vp8_extend_mb_row(&pc->yv12_fb[dst_fb_idx], xd->dst.y_buffer + 16, xd->dst.u_buffer + 8, xd->dst.v_buffer + 8);
-
-            ++xd->mode_info_context;      /* skip prediction column */
-        }
-        xd->mode_info_context += xd->mode_info_stride * pbi->decoding_thread_count;
-    }
+    decode_mb_rows(pbi, xd, 0, init_current_bc);
 
     sem_wait(&pbi->h_event_end_decoding);   /* add back for each frame */
 }
diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c
index 0bb5173..f26b4e4 100644
--- a/vp8/encoder/bitstream.c
+++ b/vp8/encoder/bitstream.c
@@ -382,219 +382,23 @@
     int i;
     unsigned char *ptr = cx_data;
     unsigned char *ptr_end = cx_data_end;
-    unsigned int shift;
-    vp8_writer *w;
-    ptr = cx_data;
+    vp8_writer * w;
 
     for (i = 0; i < num_part; i++)
     {
+        int mb_row;
+
         w = cpi->bc + i + 1;
+
         vp8_start_encode(w, ptr, ptr_end);
+
+        for (mb_row = i; mb_row < cpi->common.mb_rows; mb_row += num_part)
         {
-            unsigned int split;
-            int count = w->count;
-            unsigned int range = w->range;
-            unsigned int lowvalue = w->lowvalue;
-            int mb_row;
+            const TOKENEXTRA *p    = cpi->tplist[mb_row].start;
+            const TOKENEXTRA *stop = cpi->tplist[mb_row].stop;
+            int tokens = stop - p;
 
-            for (mb_row = i; mb_row < cpi->common.mb_rows; mb_row += num_part)
-            {
-                TOKENEXTRA *p    = cpi->tplist[mb_row].start;
-                TOKENEXTRA *stop = cpi->tplist[mb_row].stop;
-
-                while (p < stop)
-                {
-                    const int t = p->Token;
-                    vp8_token *const a = vp8_coef_encodings + t;
-                    const vp8_extra_bit_struct *const b = vp8_extra_bits + t;
-                    int i = 0;
-                    const unsigned char *pp = p->context_tree;
-                    int v = a->value;
-                    int n = a->Len;
-
-                    if (p->skip_eob_node)
-                    {
-                        n--;
-                        i = 2;
-                    }
-
-                    do
-                    {
-                        const int bb = (v >> --n) & 1;
-                        split = 1 + (((range - 1) * pp[i>>1]) >> 8);
-                        i = vp8_coef_tree[i+bb];
-
-                        if (bb)
-                        {
-                            lowvalue += split;
-                            range = range - split;
-                        }
-                        else
-                        {
-                            range = split;
-                        }
-
-                        shift = vp8_norm[range];
-                        range <<= shift;
-                        count += shift;
-
-                        if (count >= 0)
-                        {
-                            int offset = shift - count;
-
-                            if ((lowvalue << (offset - 1)) & 0x80000000)
-                            {
-                                int x = w->pos - 1;
-
-                                while (x >= 0 && w->buffer[x] == 0xff)
-                                {
-                                    w->buffer[x] = (unsigned char)0;
-                                    x--;
-                                }
-
-                                w->buffer[x] += 1;
-                            }
-
-                            validate_buffer(w->buffer + w->pos,
-                                            1,
-                                            cx_data_end,
-                                            &cpi->common.error);
-
-                            w->buffer[w->pos++] = (lowvalue >> (24 - offset));
-
-                            lowvalue <<= offset;
-                            shift = count;
-                            lowvalue &= 0xffffff;
-                            count -= 8 ;
-                        }
-
-                        lowvalue <<= shift;
-                    }
-                    while (n);
-
-
-                    if (b->base_val)
-                    {
-                        const int e = p->Extra, L = b->Len;
-
-                        if (L)
-                        {
-                            const unsigned char *pp = b->prob;
-                            int v = e >> 1;
-                            int n = L;              /* number of bits in v, assumed nonzero */
-                            int i = 0;
-
-                            do
-                            {
-                                const int bb = (v >> --n) & 1;
-                                split = 1 + (((range - 1) * pp[i>>1]) >> 8);
-                                i = b->tree[i+bb];
-
-                                if (bb)
-                                {
-                                    lowvalue += split;
-                                    range = range - split;
-                                }
-                                else
-                                {
-                                    range = split;
-                                }
-
-                                shift = vp8_norm[range];
-                                range <<= shift;
-                                count += shift;
-
-                                if (count >= 0)
-                                {
-                                    int offset = shift - count;
-
-                                    if ((lowvalue << (offset - 1)) & 0x80000000)
-                                    {
-                                        int x = w->pos - 1;
-
-                                        while (x >= 0 && w->buffer[x] == 0xff)
-                                        {
-                                            w->buffer[x] = (unsigned char)0;
-                                            x--;
-                                        }
-
-                                        w->buffer[x] += 1;
-                                    }
-
-                                    validate_buffer(w->buffer + w->pos,
-                                                    1,
-                                                    cx_data_end,
-                                                    &cpi->common.error);
-
-                                    w->buffer[w->pos++] =
-                                        (lowvalue >> (24 - offset));
-
-                                    lowvalue <<= offset;
-                                    shift = count;
-                                    lowvalue &= 0xffffff;
-                                    count -= 8 ;
-                                }
-
-                                lowvalue <<= shift;
-                            }
-                            while (n);
-                        }
-
-                        {
-                            split = (range + 1) >> 1;
-
-                            if (e & 1)
-                            {
-                                lowvalue += split;
-                                range = range - split;
-                            }
-                            else
-                            {
-                                range = split;
-                            }
-
-                            range <<= 1;
-
-                            if ((lowvalue & 0x80000000))
-                            {
-                                int x = w->pos - 1;
-
-                                while (x >= 0 && w->buffer[x] == 0xff)
-                                {
-                                    w->buffer[x] = (unsigned char)0;
-                                    x--;
-                                }
-
-                                w->buffer[x] += 1;
-
-                            }
-
-                            lowvalue  <<= 1;
-
-                            if (!++count)
-                            {
-                                count = -8;
-                                validate_buffer(w->buffer + w->pos,
-                                                1,
-                                                cx_data_end,
-                                                &cpi->common.error);
-
-                                w->buffer[w->pos++] = (lowvalue >> 24);
-
-                                lowvalue &= 0xffffff;
-                            }
-                        }
-
-                    }
-
-                    ++p;
-                }
-            }
-
-            w->count    = count;
-            w->lowvalue = lowvalue;
-            w->range    = range;
-
+            pack_tokens_c(w, p, tokens);
         }
 
         vp8_stop_encode(w);
@@ -605,209 +409,17 @@
 
 static void pack_mb_row_tokens_c(VP8_COMP *cpi, vp8_writer *w)
 {
-
-    unsigned int split;
-    int count = w->count;
-    unsigned int range = w->range;
-    unsigned int lowvalue = w->lowvalue;
-    unsigned int shift;
     int mb_row;
 
     for (mb_row = 0; mb_row < cpi->common.mb_rows; mb_row++)
     {
-        TOKENEXTRA *p    = cpi->tplist[mb_row].start;
-        TOKENEXTRA *stop = cpi->tplist[mb_row].stop;
+        const TOKENEXTRA *p    = cpi->tplist[mb_row].start;
+        const TOKENEXTRA *stop = cpi->tplist[mb_row].stop;
+        int tokens = stop - p;
 
-        while (p < stop)
-        {
-            const int t = p->Token;
-            vp8_token *const a = vp8_coef_encodings + t;
-            const vp8_extra_bit_struct *const b = vp8_extra_bits + t;
-            int i = 0;
-            const unsigned char *pp = p->context_tree;
-            int v = a->value;
-            int n = a->Len;
-
-            if (p->skip_eob_node)
-            {
-                n--;
-                i = 2;
-            }
-
-            do
-            {
-                const int bb = (v >> --n) & 1;
-                split = 1 + (((range - 1) * pp[i>>1]) >> 8);
-                i = vp8_coef_tree[i+bb];
-
-                if (bb)
-                {
-                    lowvalue += split;
-                    range = range - split;
-                }
-                else
-                {
-                    range = split;
-                }
-
-                shift = vp8_norm[range];
-                range <<= shift;
-                count += shift;
-
-                if (count >= 0)
-                {
-                    int offset = shift - count;
-
-                    if ((lowvalue << (offset - 1)) & 0x80000000)
-                    {
-                        int x = w->pos - 1;
-
-                        while (x >= 0 && w->buffer[x] == 0xff)
-                        {
-                            w->buffer[x] = (unsigned char)0;
-                            x--;
-                        }
-
-                        w->buffer[x] += 1;
-                    }
-
-                    validate_buffer(w->buffer + w->pos,
-                                    1,
-                                    w->buffer_end,
-                                    w->error);
-
-                    w->buffer[w->pos++] = (lowvalue >> (24 - offset));
-                    lowvalue <<= offset;
-                    shift = count;
-                    lowvalue &= 0xffffff;
-                    count -= 8 ;
-                }
-
-                lowvalue <<= shift;
-            }
-            while (n);
-
-
-            if (b->base_val)
-            {
-                const int e = p->Extra, L = b->Len;
-
-                if (L)
-                {
-                    const unsigned char *pp = b->prob;
-                    int v = e >> 1;
-                    int n = L;              /* number of bits in v, assumed nonzero */
-                    int i = 0;
-
-                    do
-                    {
-                        const int bb = (v >> --n) & 1;
-                        split = 1 + (((range - 1) * pp[i>>1]) >> 8);
-                        i = b->tree[i+bb];
-
-                        if (bb)
-                        {
-                            lowvalue += split;
-                            range = range - split;
-                        }
-                        else
-                        {
-                            range = split;
-                        }
-
-                        shift = vp8_norm[range];
-                        range <<= shift;
-                        count += shift;
-
-                        if (count >= 0)
-                        {
-                            int offset = shift - count;
-
-                            if ((lowvalue << (offset - 1)) & 0x80000000)
-                            {
-                                int x = w->pos - 1;
-
-                                while (x >= 0 && w->buffer[x] == 0xff)
-                                {
-                                    w->buffer[x] = (unsigned char)0;
-                                    x--;
-                                }
-
-                                w->buffer[x] += 1;
-                            }
-
-                            validate_buffer(w->buffer + w->pos,
-                                            1,
-                                            w->buffer_end,
-                                            w->error);
-
-                            w->buffer[w->pos++] = (lowvalue >> (24 - offset));
-                            lowvalue <<= offset;
-                            shift = count;
-                            lowvalue &= 0xffffff;
-                            count -= 8 ;
-                        }
-
-                        lowvalue <<= shift;
-                    }
-                    while (n);
-                }
-
-                {
-                    split = (range + 1) >> 1;
-
-                    if (e & 1)
-                    {
-                        lowvalue += split;
-                        range = range - split;
-                    }
-                    else
-                    {
-                        range = split;
-                    }
-
-                    range <<= 1;
-
-                    if ((lowvalue & 0x80000000))
-                    {
-                        int x = w->pos - 1;
-
-                        while (x >= 0 && w->buffer[x] == 0xff)
-                        {
-                            w->buffer[x] = (unsigned char)0;
-                            x--;
-                        }
-
-                        w->buffer[x] += 1;
-
-                    }
-
-                    lowvalue  <<= 1;
-
-                    if (!++count)
-                    {
-                        count = -8;
-
-                        validate_buffer(w->buffer + w->pos,
-                                        1,
-                                        w->buffer_end,
-                                        w->error);
-
-                        w->buffer[w->pos++] = (lowvalue >> 24);
-                        lowvalue &= 0xffffff;
-                    }
-                }
-
-            }
-
-            ++p;
-        }
+        pack_tokens_c(w, p, tokens);
     }
 
-    w->count = count;
-    w->lowvalue = lowvalue;
-    w->range = range;
-
 }
 
 static void write_mv_ref
@@ -925,7 +537,9 @@
 
     if (pc->mb_no_coeff_skip)
     {
-        prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count);
+        int total_mbs = pc->mb_rows * pc->mb_cols;
+
+        prob_skip_false = (total_mbs - cpi->skip_true_count ) * 256 / total_mbs;
 
         if (prob_skip_false <= 1)
             prob_skip_false = 1;
@@ -1112,7 +726,9 @@
 
     if (c->mb_no_coeff_skip)
     {
-        prob_skip_false = cpi->skip_false_count * 256 / (cpi->skip_false_count + cpi->skip_true_count);
+        int total_mbs = c->mb_rows * c->mb_cols;
+
+        prob_skip_false = (total_mbs - cpi->skip_true_count ) * 256 / total_mbs;
 
         if (prob_skip_false <= 1)
             prob_skip_false = 1;
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c
index 10f5607..9899565 100644
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -688,15 +688,12 @@
         xd->subpixel_predict16x16   = vp8_bilinear_predict16x16;
     }
 
-    // Reset frame count of inter 0,0 motion vector useage.
+    // Reset frame count of inter 0,0 motion vector usage.
     cpi->inter_zz_count = 0;
 
-    vpx_memset(segment_counts, 0, sizeof(segment_counts));
-
     cpi->prediction_error = 0;
     cpi->intra_error = 0;
     cpi->skip_true_count = 0;
-    cpi->skip_false_count = 0;
 
 #if 0
     // Experimental code
@@ -1094,6 +1091,7 @@
     vp8_encode_intra16x16mbuv(x);
 
     sum_intra_stats(cpi, x);
+
     vp8_tokenize_mb(cpi, &x->e_mbd, t);
 
     if (xd->mode_info_context->mbmi.mode != B_PRED)
@@ -1260,11 +1258,6 @@
         if (!x->skip)
         {
             vp8_encode_inter16x16(x);
-
-            // Clear mb_skip_coeff if mb_no_coeff_skip is not set
-            if (!cpi->common.mb_no_coeff_skip)
-                xd->mode_info_context->mbmi.mb_skip_coeff = 0;
-
         }
         else
             vp8_build_inter16x16_predictors_mb(xd, xd->dst.y_buffer,
@@ -1287,17 +1280,17 @@
     }
     else
     {
+        /* always set mb_skip_coeff as it is needed by the loopfilter */
+        xd->mode_info_context->mbmi.mb_skip_coeff = 1;
+
         if (cpi->common.mb_no_coeff_skip)
         {
-            xd->mode_info_context->mbmi.mb_skip_coeff = 1;
             cpi->skip_true_count ++;
             vp8_fix_contexts(xd);
         }
         else
         {
             vp8_stuff_mb(cpi, xd, t);
-            xd->mode_info_context->mbmi.mb_skip_coeff = 0;
-            cpi->skip_false_count ++;
         }
     }
 
diff --git a/vp8/encoder/ethreading.c b/vp8/encoder/ethreading.c
index 7740e5d..2874e78 100644
--- a/vp8/encoder/ethreading.c
+++ b/vp8/encoder/ethreading.c
@@ -24,9 +24,9 @@
 extern void vp8_build_block_offsets(MACROBLOCK *x);
 extern void vp8_setup_block_ptrs(MACROBLOCK *x);
 
-extern void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm);
+extern void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm);
 
-static THREAD_FUNCTION loopfilter_thread(void *p_data)
+static THREAD_FUNCTION thread_loopfilter(void *p_data)
 {
     VP8_COMP *cpi = (VP8_COMP *)(((LPFTHREAD_DATA *)p_data)->ptr1);
     VP8_COMMON *cm = &cpi->common;
@@ -41,7 +41,7 @@
             if (cpi->b_multi_threaded == 0) // we're shutting down
                 break;
 
-            loopfilter_frame(cpi, cm);
+            vp8_loopfilter_frame(cpi, cm);
 
             sem_post(&cpi->h_event_end_lpf);
         }
@@ -468,6 +468,7 @@
 
     cpi->b_multi_threaded = 0;
     cpi->encoding_thread_count = 0;
+    cpi->b_lpf_running = 0;
 
     if (cm->processor_core_count > 1 && cpi->oxcf.multi_threaded > 1)
     {
@@ -526,7 +527,7 @@
             sem_init(&cpi->h_event_end_lpf, 0, 0);
 
             lpfthd->ptr1 = (void *)cpi;
-            pthread_create(&cpi->h_filter_thread, 0, loopfilter_thread, lpfthd);
+            pthread_create(&cpi->h_filter_thread, 0, thread_loopfilter, lpfthd);
         }
     }
 
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 57656bb..6645442 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -3086,7 +3086,7 @@
     }
 }
 
-void loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm)
+void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm)
 {
     if (cm->no_lpf)
     {
@@ -3716,6 +3716,15 @@
             vp8_setup_key_frame(cpi);
         }
 
+#if CONFIG_MULTITHREAD
+        /*  wait for the last picture loopfilter thread done */
+        if (cpi->b_lpf_running)
+        {
+            sem_wait(&cpi->h_event_end_lpf);
+            cpi->b_lpf_running = 0;
+        }
+#endif
+
         // transform / motion compensation build reconstruction frame
         vp8_encode_frame(cpi);
 
@@ -4074,11 +4083,12 @@
     if (cpi->b_multi_threaded)
     {
         sem_post(&cpi->h_event_start_lpf); /* start loopfilter in separate thread */
+        cpi->b_lpf_running = 1;
     }
     else
 #endif
     {
-        loopfilter_frame(cpi, cm);
+        vp8_loopfilter_frame(cpi, cm);
     }
 
     update_reference_frames(cm);
@@ -4098,10 +4108,11 @@
     vp8_pack_bitstream(cpi, dest, dest_end, size);
 
 #if CONFIG_MULTITHREAD
-    /* wait for loopfilter thread done */
-    if (cpi->b_multi_threaded)
+    /* if PSNR packets are generated we have to wait for the lpf */
+    if (cpi->b_lpf_running && cpi->b_calculate_psnr)
     {
         sem_wait(&cpi->h_event_end_lpf);
+        cpi->b_lpf_running = 0;
     }
 #endif
 
@@ -4564,7 +4575,7 @@
     vpx_usec_timer_start(&timer);
 
     /* Reinit the lookahead buffer if the frame size changes */
-    if (sd->y_width != cpi->common.Width || sd->y_height != cpi->common.Height)
+    if (sd->y_width != cpi->oxcf.Width || sd->y_height != cpi->oxcf.Height)
     {
         assert(cpi->oxcf.lag_in_frames < 2);
         dealloc_raw_frame_buffers(cpi);
@@ -5107,6 +5118,15 @@
     else
     {
         int ret;
+
+#if CONFIG_MULTITHREAD
+        if(cpi->b_lpf_running)
+        {
+            sem_wait(&cpi->h_event_end_lpf);
+            cpi->b_lpf_running = 0;
+        }
+#endif
+
 #if CONFIG_POSTPROC
         ret = vp8_post_proc_frame(&cpi->common, dest, flags);
 #else
diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h
index 6920fc3..dcefbac 100644
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -504,7 +504,6 @@
     int gf_bad_count;
     int gf_update_recommended;
     int skip_true_count;
-    int skip_false_count;
 
     unsigned char *segmentation_map;
     signed char segment_feature_data[MB_LVL_MAX][MAX_MB_SEGMENTS];            // Segment data (can be deltas or absolute values)
@@ -526,6 +525,7 @@
     int mt_sync_range;
     int b_multi_threaded;
     int encoding_thread_count;
+    int b_lpf_running;
 
     pthread_t *h_encoding_thread;
     pthread_t h_filter_thread;
diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c
index 1c43c11..f4ed300 100644
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -392,10 +392,16 @@
         int Q = (cpi->common.frame_flags & FRAMEFLAGS_KEY)
                 ? cpi->avg_frame_qindex : cpi->ni_av_qi;
 
-        // Boost depends somewhat on frame rate
-        kf_boost = (int)(2 * cpi->output_frame_rate - 16);
+        // Boost depends somewhat on frame rate: only used for 1 layer case.
+        if (cpi->oxcf.number_of_layers == 1) {
+          kf_boost = (int)(2 * cpi->output_frame_rate - 16);
+        }
+        else {
+          // Initial factor: set target size to: |2.5 * per_frame_bandwidth|.
+          kf_boost = 24;
+        }
 
-        // adjustment up based on q
+        // adjustment up based on q: this factor ranges from ~1.2 to 2.2.
         kf_boost = kf_boost * kf_boost_qadjustment[Q] / 100;
 
         // frame separation adjustment ( down)
@@ -403,6 +409,7 @@
             kf_boost = (int)(kf_boost
                        * cpi->frames_since_key / (cpi->output_frame_rate / 2));
 
+        // Minimal target size is |2* per_frame_bandwidth|.
         if (kf_boost < 16)
             kf_boost = 16;
 
diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c
index 14000f9..80e0f4e 100644
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -1738,11 +1738,12 @@
     int rate2, distortion2;
     int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly;
     int uv_intra_tteob = 0;
+    int uv_intra_done = 0;
     int rate_y, UNINITIALIZED_IS_SAFE(rate_uv);
     int distortion_uv;
     int best_yrd = INT_MAX;
 
-    MB_PREDICTION_MODE uv_intra_mode;
+    MB_PREDICTION_MODE uv_intra_mode = 0;
     int_mv mvp;
     int near_sadidx[8] = {0, 1, 2, 3, 4, 5, 6, 7};
     int saddone=0;
@@ -1785,17 +1786,6 @@
 
     x->skip = 0;
 
-    x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME;
-    rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate, &uv_intra_rate_tokenonly, &uv_intra_distortion);
-    uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode;
-    /*
-     * Total of the eobs is used later to further adjust rate2. Since uv block's
-     * intra eobs will be overwritten when we check inter modes in following
-     * for-loop, we need to save uv_intra_tteob here.
-     */
-    for (i = 16; i < 24; i++)
-        uv_intra_tteob += x->e_mbd.eobs[i];
-
     for (mode_index = 0; mode_index < MAX_MODES; mode_index++)
     {
         int this_rd = INT_MAX;
@@ -1817,7 +1807,6 @@
         this_mode = vp8_mode_order[mode_index];
 
         x->e_mbd.mode_info_context->mbmi.mode = this_mode;
-        x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED;
         x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame;
 
         // Only consider ZEROMV/ALTREF_FRAME for alt ref frame,
@@ -1888,6 +1877,24 @@
             vp8_update_zbin_extra(cpi, x);
         }
 
+        if(!uv_intra_done && this_ref_frame == INTRA_FRAME)
+        {
+            rd_pick_intra_mbuv_mode(cpi, x, &uv_intra_rate,
+                                    &uv_intra_rate_tokenonly,
+                                    &uv_intra_distortion);
+            uv_intra_mode = x->e_mbd.mode_info_context->mbmi.uv_mode;
+
+            /*
+             * Total of the eobs is used later to further adjust rate2. Since uv
+             * block's intra eobs will be overwritten when we check inter modes,
+             * we need to save uv_intra_tteob here.
+             */
+            for (i = 16; i < 24; i++)
+                uv_intra_tteob += x->e_mbd.eobs[i];
+
+            uv_intra_done = 1;
+        }
+
         switch (this_mode)
         {
         case B_PRED:
@@ -2214,22 +2221,22 @@
             if (cpi->common.mb_no_coeff_skip)
             {
                 int tteob;
+                int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED);
 
                 tteob = 0;
+                if(has_y2_block)
+                    tteob += x->e_mbd.eobs[24];
+
+                for (i = 0; i < 16; i++)
+                    tteob += (x->e_mbd.eobs[i] > has_y2_block);
 
                 if (x->e_mbd.mode_info_context->mbmi.ref_frame)
                 {
-                    for (i = 0; i <= 24; i++)
+                    for (i = 16; i < 24; i++)
                         tteob += x->e_mbd.eobs[i];
                 }
                 else
-                {
-                    for (i = 0; i < 16; i++)
-                        tteob += x->e_mbd.eobs[i];
-
                     tteob += uv_intra_tteob;
-                    tteob += x->e_mbd.eobs[24];
-                }
 
                 if (tteob == 0)
                 {
diff --git a/vp8/encoder/tokenize.c b/vp8/encoder/tokenize.c
index 8bfc47f..967b602 100644
--- a/vp8/encoder/tokenize.c
+++ b/vp8/encoder/tokenize.c
@@ -378,30 +378,27 @@
     x->mode_info_context->mbmi.mb_skip_coeff = mb_is_skippable(x, has_y2_block);
     if (x->mode_info_context->mbmi.mb_skip_coeff)
     {
-        cpi->skip_true_count++;
-
         if (!cpi->common.mb_no_coeff_skip)
-            vp8_stuff_mb(cpi, x, t) ;
+        {
+            vp8_stuff_mb(cpi, x, t);
+        }
         else
         {
             vp8_fix_contexts(x);
+            cpi->skip_true_count++;
         }
 
         return;
     }
 
-    cpi->skip_false_count++;
-
     plane_type = 3;
     if(has_y2_block)
     {
         tokenize2nd_order_b(x, t, cpi);
         plane_type = 0;
-
     }
 
     tokenize1st_order_b(x, t, plane_type, cpi);
-
 }
 
 
diff --git a/vp8/vp8_common.mk b/vp8/vp8_common.mk
index b2db4ce..a200b22 100644
--- a/vp8/vp8_common.mk
+++ b/vp8/vp8_common.mk
@@ -30,6 +30,7 @@
 VP8_COMMON_SRCS-yes += common/generic/systemdependent.c
 VP8_COMMON_SRCS-yes += common/idct_blk.c
 VP8_COMMON_SRCS-yes += common/idctllm.c
+VP8_COMMON_SRCS-yes += common/idctllm_test.cc
 VP8_COMMON_SRCS-yes += common/alloccommon.h
 VP8_COMMON_SRCS-yes += common/blockd.h
 VP8_COMMON_SRCS-yes += common/common.h
@@ -80,6 +81,7 @@
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/dequantize_mmx.asm
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idct_blk_mmx.c
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idctllm_mmx.asm
+VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/idctllm_mmx_test.cc
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/iwalsh_mmx.asm
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/recon_mmx.asm
 VP8_COMMON_SRCS-$(HAVE_MMX) += common/x86/subpixel_mmx.asm
diff --git a/vpxenc.c b/vpxenc.c
index bb0a306..7d6758a 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -116,13 +116,17 @@
 }
 
 
-static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s)
+static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...)
 {
+    va_list ap;
+
+    va_start(ap, s);
     if (ctx->err)
     {
         const char *detail = vpx_codec_error_detail(ctx);
 
-        fprintf(stderr, "%s: %s\n", s, vpx_codec_error(ctx));
+        vfprintf(stderr, s, ap);
+        fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
 
         if (detail)
             fprintf(stderr, "    %s\n", detail);
@@ -1480,8 +1484,6 @@
     const struct codec_item  *codec;
     int                       passes;
     int                       pass;
-    const char               *stats_fn;
-    const char               *out_fn;
     int                       usage;
     int                       deadline;
     int                       use_i420;
@@ -1490,13 +1492,47 @@
     int                       show_psnr;
     int                       have_framerate;
     struct vpx_rational       framerate;
-    int                       write_webm;
     int                       debug;
     int                       show_q_hist_buckets;
     int                       show_rate_hist_buckets;
 };
 
 
+/* Per-stream configuration */
+struct stream_config
+{
+    struct vpx_codec_enc_cfg  cfg;
+    const char               *out_fn;
+    const char               *stats_fn;
+    stereo_format_t           stereo_fmt;
+    int                       arg_ctrls[ARG_CTRL_CNT_MAX][2];
+    int                       arg_ctrl_cnt;
+    int                       write_webm;
+};
+
+
+struct stream_state
+{
+    int                       index;
+    struct stream_state      *next;
+    struct stream_config      config;
+    FILE                     *file;
+    struct rate_hist          rate_hist;
+    EbmlGlobal                ebml;
+    uint32_t                  hash;
+    uint64_t                  psnr_sse_total;
+    uint64_t                  psnr_samples_total;
+    double                    psnr_totals[4];
+    int                       psnr_count;
+    int                       counts[64];
+    vpx_codec_ctx_t           encoder;
+    unsigned int              frames_out;
+    uint64_t                  cx_time;
+    size_t                    nbytes;
+    stats_io_t                stats;
+};
+
+
 static void parse_global_config(struct global_config *global, char **argv)
 {
     char       **argi, **argj;
@@ -1507,7 +1543,6 @@
     global->codec = codecs;
     global->passes = 1;
     global->use_i420 = 1;
-    global->write_webm = 1;
 
     for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
     {
@@ -1543,8 +1578,6 @@
                 die("Error: Invalid pass selected (%d)\n",
                     global->pass);
         }
-        else if (arg_match(&arg, &fpf_name, argi))
-            global->stats_fn = arg.val;
         else if (arg_match(&arg, &usage, argi))
             global->usage = arg_parse_uint(&arg);
         else if (arg_match(&arg, &deadline, argi))
@@ -1570,10 +1603,6 @@
             global->framerate = arg_parse_rational(&arg);
             global->have_framerate = 1;
         }
-        else if (arg_match(&arg, &use_ivf, argi))
-            global->write_webm = 0;
-        else if (arg_match(&arg, &outputfile, argi))
-            global->out_fn = arg.val;
         else if (arg_match(&arg, &debugmode, argi))
             global->debug = 1;
         else if (arg_match(&arg, &q_hist_n, argi))
@@ -1586,9 +1615,6 @@
 
     /* Validate global config */
 
-    /* Ensure that --passes and --pass are consistent. If --pass is set and
-     * --passes=2, ensure --fpf was set.
-     */
     if (global->pass)
     {
         /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
@@ -1598,10 +1624,6 @@
                  global->pass, global->pass);
             global->passes = global->pass;
         }
-
-        if (global->passes == 2 && !global->stats_fn)
-            die("Must specify --fpf when --pass=%d and --passes=2\n",
-                global->pass);
     }
 }
 
@@ -1667,44 +1689,578 @@
         y4m_input_close(&input->y4m);
 }
 
+static struct stream_state *new_stream(struct global_config *global,
+                                       struct stream_state  *prev)
+{
+    struct stream_state *stream;
+
+    stream = calloc(1, sizeof(*stream));
+    if(!stream)
+        fatal("Failed to allocate new stream.");
+    if(prev)
+    {
+        memcpy(stream, prev, sizeof(*stream));
+        stream->index++;
+        prev->next = stream;
+    }
+    else
+    {
+        vpx_codec_err_t  res;
+
+        /* Populate encoder configuration */
+        res = vpx_codec_enc_config_default(global->codec->iface,
+                                           &stream->config.cfg,
+                                           global->usage);
+        if (res)
+            fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res));
+
+        /* Change the default timebase to a high enough value so that the
+         * encoder will always create strictly increasing timestamps.
+         */
+        stream->config.cfg.g_timebase.den = 1000;
+
+        /* Never use the library's default resolution, require it be parsed
+         * from the file or set on the command line.
+         */
+        stream->config.cfg.g_w = 0;
+        stream->config.cfg.g_h = 0;
+
+        /* Initialize remaining stream parameters */
+        stream->config.stereo_fmt = STEREO_FORMAT_MONO;
+        stream->config.write_webm = 1;
+        stream->ebml.last_pts_ms = -1;
+    }
+
+    /* Output files must be specified for each stream */
+    stream->config.out_fn = NULL;
+
+    stream->next = NULL;
+    return stream;
+}
+
+
+static int parse_stream_params(struct global_config *global,
+                               struct stream_state  *stream,
+                               char **argv)
+{
+    char                   **argi, **argj;
+    struct arg               arg;
+    static const arg_def_t **ctrl_args = no_args;
+    static const int        *ctrl_args_map = NULL;
+    struct stream_config    *config = &stream->config;
+    int                      eos_mark_found = 0;
+
+    /* Handle codec specific options */
+    if (global->codec->iface == &vpx_codec_vp8_cx_algo)
+    {
+        ctrl_args = vp8_args;
+        ctrl_args_map = vp8_arg_ctrl_map;
+    }
+
+    for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
+    {
+        arg.argv_step = 1;
+
+        /* Once we've found an end-of-stream marker (--) we want to continue
+         * shifting arguments but not consuming them.
+         */
+        if (eos_mark_found)
+        {
+            argj++;
+            continue;
+        }
+        else if (!strcmp(*argj, "--"))
+        {
+            eos_mark_found = 1;
+            continue;
+        }
+
+        if (0);
+        else if (arg_match(&arg, &outputfile, argi))
+            config->out_fn = arg.val;
+        else if (arg_match(&arg, &fpf_name, argi))
+            config->stats_fn = arg.val;
+        else if (arg_match(&arg, &use_ivf, argi))
+            config->write_webm = 0;
+        else if (arg_match(&arg, &threads, argi))
+            config->cfg.g_threads = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &profile, argi))
+            config->cfg.g_profile = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &width, argi))
+            config->cfg.g_w = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &height, argi))
+            config->cfg.g_h = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &stereo_mode, argi))
+            config->stereo_fmt = arg_parse_enum_or_int(&arg);
+        else if (arg_match(&arg, &timebase, argi))
+            config->cfg.g_timebase = arg_parse_rational(&arg);
+        else if (arg_match(&arg, &error_resilient, argi))
+            config->cfg.g_error_resilient = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &lag_in_frames, argi))
+            config->cfg.g_lag_in_frames = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &dropframe_thresh, argi))
+            config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &resize_allowed, argi))
+            config->cfg.rc_resize_allowed = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &resize_up_thresh, argi))
+            config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &resize_down_thresh, argi))
+            config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &end_usage, argi))
+            config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
+        else if (arg_match(&arg, &target_bitrate, argi))
+            config->cfg.rc_target_bitrate = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &min_quantizer, argi))
+            config->cfg.rc_min_quantizer = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &max_quantizer, argi))
+            config->cfg.rc_max_quantizer = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &undershoot_pct, argi))
+            config->cfg.rc_undershoot_pct = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &overshoot_pct, argi))
+            config->cfg.rc_overshoot_pct = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &buf_sz, argi))
+            config->cfg.rc_buf_sz = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &buf_initial_sz, argi))
+            config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &buf_optimal_sz, argi))
+            config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &bias_pct, argi))
+        {
+            config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
+
+            if (global->passes < 2)
+                warn("option %s ignored in one-pass mode.\n", arg.name);
+        }
+        else if (arg_match(&arg, &minsection_pct, argi))
+        {
+            config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);
+
+            if (global->passes < 2)
+                warn("option %s ignored in one-pass mode.\n", arg.name);
+        }
+        else if (arg_match(&arg, &maxsection_pct, argi))
+        {
+            config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);
+
+            if (global->passes < 2)
+                warn("option %s ignored in one-pass mode.\n", arg.name);
+        }
+        else if (arg_match(&arg, &kf_min_dist, argi))
+            config->cfg.kf_min_dist = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &kf_max_dist, argi))
+            config->cfg.kf_max_dist = arg_parse_uint(&arg);
+        else if (arg_match(&arg, &kf_disabled, argi))
+            config->cfg.kf_mode = VPX_KF_DISABLED;
+        else
+        {
+            int i, match = 0;
+
+            for (i = 0; ctrl_args[i]; i++)
+            {
+                if (arg_match(&arg, ctrl_args[i], argi))
+                {
+                    int j;
+                    match = 1;
+
+                    /* Point either to the next free element or the first
+                    * instance of this control.
+                    */
+                    for(j=0; j<config->arg_ctrl_cnt; j++)
+                        if(config->arg_ctrls[j][0] == ctrl_args_map[i])
+                            break;
+
+                    /* Update/insert */
+                    assert(j < ARG_CTRL_CNT_MAX);
+                    if (j < ARG_CTRL_CNT_MAX)
+                    {
+                        config->arg_ctrls[j][0] = ctrl_args_map[i];
+                        config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg);
+                        if(j == config->arg_ctrl_cnt)
+                            config->arg_ctrl_cnt++;
+                    }
+
+                }
+            }
+
+            if (!match)
+                argj++;
+        }
+    }
+
+    return eos_mark_found;
+}
+
+
+#define FOREACH_STREAM(func)\
+do\
+{\
+    struct stream_state  *stream;\
+\
+    for(stream = streams; stream; stream = stream->next)\
+        func;\
+}while(0)
+
+
+static void validate_stream_config(struct stream_state *stream)
+{
+    struct stream_state *streami;
+
+    if(!stream->config.cfg.g_w || !stream->config.cfg.g_h)
+        fatal("Stream %d: Specify stream dimensions with --width (-w) "
+              " and --height (-h)", stream->index);
+
+    for(streami = stream; streami; streami = streami->next)
+    {
+        /* All streams require output files */
+        if(!streami->config.out_fn)
+            fatal("Stream %d: Output file is required (specify with -o)",
+                  streami->index);
+
+        /* Check for two streams outputting to the same file */
+        if(streami != stream)
+        {
+            const char *a = stream->config.out_fn;
+            const char *b = streami->config.out_fn;
+            if(!strcmp(a,b) && strcmp(a, "/dev/null") && strcmp(a, ":nul"))
+                fatal("Stream %d: duplicate output file (from stream %d)",
+                      streami->index, stream->index);
+        }
+
+        /* Check for two streams sharing a stats file. */
+        if(streami != stream)
+        {
+            const char *a = stream->config.stats_fn;
+            const char *b = streami->config.stats_fn;
+            if(a && b && !strcmp(a,b))
+                fatal("Stream %d: duplicate stats file (from stream %d)",
+                      streami->index, stream->index);
+        }
+    }
+}
+
+
+static void set_stream_dimensions(struct stream_state *stream,
+                                  unsigned int w,
+                                  unsigned int h)
+{
+    if ((stream->config.cfg.g_w && stream->config.cfg.g_w != w)
+        ||(stream->config.cfg.g_h && stream->config.cfg.g_h != h))
+        fatal("Stream %d: Resizing not yet supported", stream->index);
+    stream->config.cfg.g_w = w;
+    stream->config.cfg.g_h = h;
+}
+
+
+static void show_stream_config(struct stream_state  *stream,
+                               struct global_config *global,
+                               struct input_state   *input)
+{
+
+#define SHOW(field) \
+    fprintf(stderr, "    %-28s = %d\n", #field, stream->config.cfg.field)
+
+    if(stream->index == 0)
+    {
+        fprintf(stderr, "Codec: %s\n",
+                vpx_codec_iface_name(global->codec->iface));
+        fprintf(stderr, "Source file: %s Format: %s\n", input->fn,
+                input->use_i420 ? "I420" : "YV12");
+    }
+    if(stream->next || stream->index)
+        fprintf(stderr, "\nStream Index: %d\n", stream->index);
+    fprintf(stderr, "Destination file: %s\n", stream->config.out_fn);
+    fprintf(stderr, "Encoder parameters:\n");
+
+    SHOW(g_usage);
+    SHOW(g_threads);
+    SHOW(g_profile);
+    SHOW(g_w);
+    SHOW(g_h);
+    SHOW(g_timebase.num);
+    SHOW(g_timebase.den);
+    SHOW(g_error_resilient);
+    SHOW(g_pass);
+    SHOW(g_lag_in_frames);
+    SHOW(rc_dropframe_thresh);
+    SHOW(rc_resize_allowed);
+    SHOW(rc_resize_up_thresh);
+    SHOW(rc_resize_down_thresh);
+    SHOW(rc_end_usage);
+    SHOW(rc_target_bitrate);
+    SHOW(rc_min_quantizer);
+    SHOW(rc_max_quantizer);
+    SHOW(rc_undershoot_pct);
+    SHOW(rc_overshoot_pct);
+    SHOW(rc_buf_sz);
+    SHOW(rc_buf_initial_sz);
+    SHOW(rc_buf_optimal_sz);
+    SHOW(rc_2pass_vbr_bias_pct);
+    SHOW(rc_2pass_vbr_minsection_pct);
+    SHOW(rc_2pass_vbr_maxsection_pct);
+    SHOW(kf_mode);
+    SHOW(kf_min_dist);
+    SHOW(kf_max_dist);
+}
+
+
+static void open_output_file(struct stream_state *stream,
+                             struct global_config *global)
+{
+    const char *fn = stream->config.out_fn;
+
+    stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout);
+
+    if (!stream->file)
+        fatal("Failed to open output file");
+
+    if(stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR))
+        fatal("WebM output to pipes not supported.");
+
+    if(stream->config.write_webm)
+    {
+        stream->ebml.stream = stream->file;
+        write_webm_file_header(&stream->ebml, &stream->config.cfg,
+                               &global->framerate,
+                               stream->config.stereo_fmt);
+    }
+    else
+        write_ivf_file_header(stream->file, &stream->config.cfg,
+                              global->codec->fourcc, 0);
+}
+
+
+static void close_output_file(struct stream_state *stream,
+                              unsigned int         fourcc)
+{
+    if(stream->config.write_webm)
+    {
+        write_webm_file_footer(&stream->ebml, stream->hash);
+        free(stream->ebml.cue_list);
+        stream->ebml.cue_list = NULL;
+    }
+    else
+    {
+        if (!fseek(stream->file, 0, SEEK_SET))
+            write_ivf_file_header(stream->file, &stream->config.cfg,
+                                  fourcc,
+                                  stream->frames_out);
+    }
+
+    fclose(stream->file);
+}
+
+
+static void setup_pass(struct stream_state  *stream,
+                       struct global_config *global,
+                       int                   pass)
+{
+    if (stream->config.stats_fn)
+    {
+        if (!stats_open_file(&stream->stats, stream->config.stats_fn,
+                             pass))
+            fatal("Failed to open statistics store");
+    }
+    else
+    {
+        if (!stats_open_mem(&stream->stats, pass))
+            fatal("Failed to open statistics store");
+    }
+
+    stream->config.cfg.g_pass = global->passes == 2
+        ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS
+        : VPX_RC_ONE_PASS;
+    if (pass)
+        stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats);
+}
+
+
+static void initialize_encoder(struct stream_state  *stream,
+                               struct global_config *global)
+{
+    int i;
+
+    /* Construct Encoder Context */
+    vpx_codec_enc_init(&stream->encoder, global->codec->iface,
+                       &stream->config.cfg,
+                       global->show_psnr ? VPX_CODEC_USE_PSNR : 0);
+    ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder");
+
+    /* Note that we bypass the vpx_codec_control wrapper macro because
+     * we're being clever to store the control IDs in an array. Real
+     * applications will want to make use of the enumerations directly
+     */
+    for (i = 0; i < stream->config.arg_ctrl_cnt; i++)
+    {
+        int ctrl = stream->config.arg_ctrls[i][0];
+        int value = stream->config.arg_ctrls[i][1];
+        if (vpx_codec_control_(&stream->encoder, ctrl, value))
+            fprintf(stderr, "Error: Tried to set control %d = %d\n",
+                    ctrl, value);
+
+        ctx_exit_on_error(&stream->encoder, "Failed to control codec");
+    }
+}
+
+
+static void encode_frame(struct stream_state  *stream,
+                         struct global_config *global,
+                         struct vpx_image     *img,
+                         unsigned int          frames_in)
+{
+    vpx_codec_pts_t frame_start, next_frame_start;
+    struct vpx_codec_enc_cfg *cfg = &stream->config.cfg;
+    struct vpx_usec_timer timer;
+
+    frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1)
+                  * global->framerate.den)
+                  / cfg->g_timebase.num / global->framerate.num;
+    next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in)
+                        * global->framerate.den)
+                        / cfg->g_timebase.num / global->framerate.num;
+    vpx_usec_timer_start(&timer);
+    vpx_codec_encode(&stream->encoder, img, frame_start,
+                     next_frame_start - frame_start,
+                     0, global->deadline);
+    vpx_usec_timer_mark(&timer);
+    stream->cx_time += vpx_usec_timer_elapsed(&timer);
+    ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame",
+                      stream->index);
+}
+
+
+static void update_quantizer_histogram(struct stream_state *stream)
+{
+    if(stream->config.cfg.g_pass != VPX_RC_FIRST_PASS)
+    {
+        int q;
+
+        vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q);
+        ctx_exit_on_error(&stream->encoder, "Failed to read quantizer");
+        stream->counts[q]++;
+    }
+}
+
+
+static void get_cx_data(struct stream_state  *stream,
+                        struct global_config *global,
+                        int                  *got_data)
+{
+    const vpx_codec_cx_pkt_t *pkt;
+    const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg;
+    vpx_codec_iter_t iter = NULL;
+
+    while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter)))
+    {
+        *got_data = 1;
+
+        switch (pkt->kind)
+        {
+        case VPX_CODEC_CX_FRAME_PKT:
+            stream->frames_out++;
+            fprintf(stderr, " %6luF",
+                    (unsigned long)pkt->data.frame.sz);
+
+            update_rate_histogram(&stream->rate_hist, cfg, pkt);
+            if(stream->config.write_webm)
+            {
+                /* Update the hash */
+                if(!stream->ebml.debug)
+                    stream->hash = murmur(pkt->data.frame.buf,
+                                          pkt->data.frame.sz, stream->hash);
+
+                write_webm_block(&stream->ebml, cfg, pkt);
+            }
+            else
+            {
+                write_ivf_frame_header(stream->file, pkt);
+                if(fwrite(pkt->data.frame.buf, 1,
+                          pkt->data.frame.sz, stream->file));
+            }
+            stream->nbytes += pkt->data.raw.sz;
+            break;
+        case VPX_CODEC_STATS_PKT:
+            stream->frames_out++;
+            fprintf(stderr, " %6luS",
+                   (unsigned long)pkt->data.twopass_stats.sz);
+            stats_write(&stream->stats,
+                        pkt->data.twopass_stats.buf,
+                        pkt->data.twopass_stats.sz);
+            stream->nbytes += pkt->data.raw.sz;
+            break;
+        case VPX_CODEC_PSNR_PKT:
+
+            if (global->show_psnr)
+            {
+                int i;
+
+                stream->psnr_sse_total += pkt->data.psnr.sse[0];
+                stream->psnr_samples_total += pkt->data.psnr.samples[0];
+                for (i = 0; i < 4; i++)
+                {
+                    fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]);
+                    stream->psnr_totals[i] += pkt->data.psnr.psnr[i];
+                }
+                stream->psnr_count++;
+            }
+
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+
+static void show_psnr(struct stream_state  *stream)
+{
+    int i;
+    double ovpsnr;
+
+    if (!stream->psnr_count)
+        return;
+
+    fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index);
+    ovpsnr = vp8_mse2psnr(stream->psnr_samples_total, 255.0,
+                          stream->psnr_sse_total);
+    fprintf(stderr, " %.3lf", ovpsnr);
+
+    for (i = 0; i < 4; i++)
+    {
+        fprintf(stderr, " %.3lf", stream->psnr_totals[i]/stream->psnr_count);
+    }
+    fprintf(stderr, "\n");
+}
+
+
+float usec_to_fps(uint64_t usec, unsigned int frames)
+{
+    return usec > 0 ? (float)frames * 1000000.0 / (float)usec : 0;
+}
+
 
 int main(int argc, const char **argv_)
 {
-    vpx_codec_ctx_t        encoder;
-    int                    i;
-    FILE                  *outfile;
-    vpx_codec_enc_cfg_t    cfg;
-    vpx_codec_err_t        res;
     int                    pass;
-    stats_io_t             stats;
     vpx_image_t            raw;
     int                    frame_avail, got_data;
 
     struct input_state       input = {0};
     struct global_config     global;
-    struct arg               arg;
-    char                   **argv, **argi, **argj;
-    int                      arg_ctrls[ARG_CTRL_CNT_MAX][2], arg_ctrl_cnt = 0;
-    static const arg_def_t **ctrl_args = no_args;
-    static const int        *ctrl_args_map = NULL;
+    struct stream_state     *streams = NULL;
+    char                   **argv, **argi;
     unsigned long            cx_time = 0;
-
-    EbmlGlobal               ebml = {0};
-    uint32_t                 hash = 0;
-    uint64_t                 psnr_sse_total = 0;
-    uint64_t                 psnr_samples_total = 0;
-    double                   psnr_totals[4] = {0, 0, 0, 0};
-    int                      psnr_count = 0;
-    stereo_format_t          stereo_fmt = STEREO_FORMAT_MONO;
-    int                      counts[64]={0};
-    struct rate_hist         rate_hist={0};
+    int                      stream_cnt = 0;
 
     exec_name = argv_[0];
-    ebml.last_pts_ms = -1;
 
     if (argc < 3)
         usage_exit();
 
+    /* Setup default input stream settings */
+    input.framerate.num = 30;
+    input.framerate.den = 1;
+    input.use_i420 = 1;
+
     /* First parse the global configuration values, because we want to apply
      * other parameters on top of the default configuration provided by the
      * codec.
@@ -1712,154 +2268,20 @@
     argv = argv_dup(argc - 1, argv_ + 1);
     parse_global_config(&global, argv);
 
-    /* Populate encoder configuration */
-    res = vpx_codec_enc_config_default(global.codec->iface, &cfg,
-                                       global.usage);
-
-    if (res)
-        fatal("Failed to get config: %s", vpx_codec_err_to_string(res));
-
-    /* Change the default timebase to a high enough value so that the encoder
-     * will always create strictly increasing timestamps.
-     */
-    cfg.g_timebase.den = 1000;
-
-    /* Never use the library's default resolution, require it be parsed
-     * from the file or set on the command line.
-     */
-    cfg.g_w = 0;
-    cfg.g_h = 0;
-
-    /* Setup default input stream settings */
-    input.framerate.num = 30;
-    input.framerate.den = 1;
-    input.use_i420 = 1;
-
-    /* Now parse the remainder of the parameters. */
-    for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
     {
-        arg.argv_step = 1;
+        /* Now parse each stream's parameters. Using a local scope here
+         * due to the use of 'stream' as loop variable in FOREACH_STREAM
+         * loops
+         */
+        struct stream_state *stream = NULL;
 
-        if (0);
-        else if (arg_match(&arg, &threads, argi))
-            cfg.g_threads = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &profile, argi))
-            cfg.g_profile = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &width, argi))
-            cfg.g_w = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &height, argi))
-            cfg.g_h = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &stereo_mode, argi))
-            stereo_fmt = arg_parse_enum_or_int(&arg);
-        else if (arg_match(&arg, &timebase, argi))
-            cfg.g_timebase = arg_parse_rational(&arg);
-        else if (arg_match(&arg, &error_resilient, argi))
-            cfg.g_error_resilient = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &lag_in_frames, argi))
-            cfg.g_lag_in_frames = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &dropframe_thresh, argi))
-            cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &resize_allowed, argi))
-            cfg.rc_resize_allowed = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &resize_up_thresh, argi))
-            cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &resize_down_thresh, argi))
-            cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &end_usage, argi))
-            cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
-        else if (arg_match(&arg, &target_bitrate, argi))
-            cfg.rc_target_bitrate = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &min_quantizer, argi))
-            cfg.rc_min_quantizer = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &max_quantizer, argi))
-            cfg.rc_max_quantizer = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &undershoot_pct, argi))
-            cfg.rc_undershoot_pct = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &overshoot_pct, argi))
-            cfg.rc_overshoot_pct = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &buf_sz, argi))
-            cfg.rc_buf_sz = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &buf_initial_sz, argi))
-            cfg.rc_buf_initial_sz = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &buf_optimal_sz, argi))
-            cfg.rc_buf_optimal_sz = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &bias_pct, argi))
+        do
         {
-            cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
-
-            if (global.passes < 2)
-                warn("option %s ignored in one-pass mode.\n", arg.name);
-        }
-        else if (arg_match(&arg, &minsection_pct, argi))
-        {
-            cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);
-
-            if (global.passes < 2)
-                warn("option %s ignored in one-pass mode.\n", arg.name);
-        }
-        else if (arg_match(&arg, &maxsection_pct, argi))
-        {
-            cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);
-
-            if (global.passes < 2)
-                warn("option %s ignored in one-pass mode.\n", arg.name);
-        }
-        else if (arg_match(&arg, &kf_min_dist, argi))
-            cfg.kf_min_dist = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &kf_max_dist, argi))
-            cfg.kf_max_dist = arg_parse_uint(&arg);
-        else if (arg_match(&arg, &kf_disabled, argi))
-            cfg.kf_mode = VPX_KF_DISABLED;
-        else
-            argj++;
-    }
-
-    /* Handle codec specific options */
-#if CONFIG_VP8_ENCODER
-
-    if (global.codec->iface == &vpx_codec_vp8_cx_algo)
-    {
-        ctrl_args = vp8_args;
-        ctrl_args_map = vp8_arg_ctrl_map;
-    }
-
-#endif
-
-    for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
-    {
-        int match = 0;
-
-        arg.argv_step = 1;
-
-        for (i = 0; ctrl_args[i]; i++)
-        {
-            if (arg_match(&arg, ctrl_args[i], argi))
-            {
-                int j;
-                match = 1;
-
-                /* Point either to the next free element or the first
-                * instance of this control.
-                */
-                for(j=0; j<arg_ctrl_cnt; j++)
-                    if(arg_ctrls[j][0] == ctrl_args_map[i])
-                        break;
-
-                /* Update/insert */
-                assert(j < ARG_CTRL_CNT_MAX);
-                if (j < ARG_CTRL_CNT_MAX)
-                {
-                    arg_ctrls[j][0] = ctrl_args_map[i];
-                    arg_ctrls[j][1] = arg_parse_enum_or_int(&arg);
-                    if(j == arg_ctrl_cnt)
-                        arg_ctrl_cnt++;
-                }
-
-            }
-        }
-
-        if (!match)
-            argj++;
+            stream = new_stream(&global, stream);
+            stream_cnt++;
+            if(!streams)
+                streams = stream;
+        } while(parse_stream_params(&global, stream, argv));
     }
 
     /* Check for unrecognized options */
@@ -1873,28 +2295,39 @@
     if (!input.fn)
         usage_exit();
 
-    if(!global.out_fn)
-        die("Error: Output file is required (specify with -o)\n");
-
-    memset(&stats, 0, sizeof(stats));
-
     for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++)
     {
-        int frames_in = 0, frames_out = 0;
-        int64_t nbytes = 0;
+        int frames_in = 0;
 
         open_input_file(&input);
 
-        /* Update configuration settings parsed from the file */
-        if(input.w && input.h)
-        {
-            cfg.g_w = input.w;
-            cfg.g_h = input.h;
-        }
+        /* If the input file doesn't specify its w/h (raw files), try to get
+         * the data from the first stream's configuration.
+         */
+        if(!input.w || !input.h)
+            FOREACH_STREAM({
+                if(stream->config.cfg.g_w && stream->config.cfg.g_h)
+                {
+                    input.w = stream->config.cfg.g_w;
+                    input.h = stream->config.cfg.g_h;
+                    break;
+                }
+            });
 
-        if(!cfg.g_w || !cfg.g_h)
-            fatal("Specify stream dimensions with --width (-w) "
-                  " and --height (-h).\n");
+        /* Update stream configurations from the input file's parameters */
+        FOREACH_STREAM(set_stream_dimensions(stream, input.w, input.h));
+        FOREACH_STREAM(validate_stream_config(stream));
+
+        /* Ensure that --passes and --pass are consistent. If --pass is set and
+         * --passes=2, ensure --fpf was set.
+         */
+        if (global.pass && global.passes == 2)
+            FOREACH_STREAM({
+                if(!stream->config.stats_fn)
+                    die("Stream %d: Must specify --fpf when --pass=%d"
+                        " and --passes=2\n", stream->index, global.pass);
+            });
+
 
         /* Use the frame rate from the file only if none was specified
          * on the command-line.
@@ -1902,48 +2335,9 @@
         if (!global.have_framerate)
             global.framerate = input.framerate;
 
-
-#define SHOW(field) fprintf(stderr, "    %-28s = %d\n", #field, cfg.field)
-
+        /* Show configuration */
         if (global.verbose && pass == 0)
-        {
-            fprintf(stderr, "Codec: %s\n",
-                    vpx_codec_iface_name(global.codec->iface));
-            fprintf(stderr, "Source file: %s Format: %s\n", input.fn,
-                    global.use_i420 ? "I420" : "YV12");
-            fprintf(stderr, "Destination file: %s\n", global.out_fn);
-            fprintf(stderr, "Encoder parameters:\n");
-
-            SHOW(g_usage);
-            SHOW(g_threads);
-            SHOW(g_profile);
-            SHOW(g_w);
-            SHOW(g_h);
-            SHOW(g_timebase.num);
-            SHOW(g_timebase.den);
-            SHOW(g_error_resilient);
-            SHOW(g_pass);
-            SHOW(g_lag_in_frames);
-            SHOW(rc_dropframe_thresh);
-            SHOW(rc_resize_allowed);
-            SHOW(rc_resize_up_thresh);
-            SHOW(rc_resize_down_thresh);
-            SHOW(rc_end_usage);
-            SHOW(rc_target_bitrate);
-            SHOW(rc_min_quantizer);
-            SHOW(rc_max_quantizer);
-            SHOW(rc_undershoot_pct);
-            SHOW(rc_overshoot_pct);
-            SHOW(rc_buf_sz);
-            SHOW(rc_buf_initial_sz);
-            SHOW(rc_buf_optimal_sz);
-            SHOW(rc_2pass_vbr_bias_pct);
-            SHOW(rc_2pass_vbr_minsection_pct);
-            SHOW(rc_2pass_vbr_maxsection_pct);
-            SHOW(kf_mode);
-            SHOW(kf_min_dist);
-            SHOW(kf_max_dist);
-        }
+            FOREACH_STREAM(show_stream_config(stream, &global, &input));
 
         if(pass == (global.pass ? global.pass - 1 : 0)) {
             if (input.file_type == FILE_TYPE_Y4M)
@@ -1952,80 +2346,26 @@
                    frames.*/
                 memset(&raw, 0, sizeof(raw));
             else
-                vpx_img_alloc(&raw, global.use_i420 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_YV12,
-                              cfg.g_w, cfg.g_h, 1);
+                vpx_img_alloc(&raw,
+                              input.use_i420 ? VPX_IMG_FMT_I420
+                                             : VPX_IMG_FMT_YV12,
+                              input.w, input.h, 1);
 
-            init_rate_histogram(&rate_hist, &cfg, &global.framerate);
+            FOREACH_STREAM(init_rate_histogram(&stream->rate_hist,
+                                               &stream->config.cfg,
+                                               &global.framerate));
         }
 
-        outfile = strcmp(global.out_fn, "-") ? fopen(global.out_fn, "wb")
-                                             : set_binary_mode(stdout);
-
-        if (!outfile)
-            fatal("Failed to open output file");
-
-        if(global.write_webm && fseek(outfile, 0, SEEK_CUR))
-            fatal("WebM output to pipes not supported.");
-
-        if (global.stats_fn)
-        {
-            if (!stats_open_file(&stats, global.stats_fn, pass))
-                fatal("Failed to open statistics store");
-        }
-        else
-        {
-            if (!stats_open_mem(&stats, pass))
-                fatal("Failed to open statistics store");
-        }
-
-        cfg.g_pass = global.passes == 2
-                     ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS
-                 : VPX_RC_ONE_PASS;
-#if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
-
-        if (pass)
-        {
-            cfg.rc_twopass_stats_in = stats_get(&stats);
-        }
-
-#endif
-
-        if(global.write_webm)
-        {
-            ebml.stream = outfile;
-            write_webm_file_header(&ebml, &cfg, &global.framerate, stereo_fmt);
-        }
-        else
-            write_ivf_file_header(outfile, &cfg, global.codec->fourcc, 0);
-
-
-        /* Construct Encoder Context */
-        vpx_codec_enc_init(&encoder, global.codec->iface, &cfg,
-                           global.show_psnr ? VPX_CODEC_USE_PSNR : 0);
-        ctx_exit_on_error(&encoder, "Failed to initialize encoder");
-
-        /* Note that we bypass the vpx_codec_control wrapper macro because
-         * we're being clever to store the control IDs in an array. Real
-         * applications will want to make use of the enumerations directly
-         */
-        for (i = 0; i < arg_ctrl_cnt; i++)
-        {
-            if (vpx_codec_control_(&encoder, arg_ctrls[i][0], arg_ctrls[i][1]))
-                fprintf(stderr, "Error: Tried to set control %d = %d\n",
-                        arg_ctrls[i][0], arg_ctrls[i][1]);
-
-            ctx_exit_on_error(&encoder, "Failed to control codec");
-        }
+        FOREACH_STREAM(open_output_file(stream, &global));
+        FOREACH_STREAM(setup_pass(stream, &global, pass));
+        FOREACH_STREAM(initialize_encoder(stream, &global));
 
         frame_avail = 1;
         got_data = 0;
 
         while (frame_avail || got_data)
         {
-            vpx_codec_iter_t iter = NULL;
-            const vpx_codec_cx_pkt_t *pkt;
             struct vpx_usec_timer timer;
-            int64_t frame_start, next_frame_start;
 
             if (!global.limit || frames_in < global.limit)
             {
@@ -2034,157 +2374,80 @@
                 if (frame_avail)
                     frames_in++;
 
-                fprintf(stderr,
-                        "\rPass %d/%d frame %4d/%-4d %7"PRId64"B \033[K",
-                        pass + 1, global.passes, frames_in, frames_out, nbytes);
+                if(stream_cnt == 1)
+                    fprintf(stderr,
+                            "\rPass %d/%d frame %4d/%-4d %7"PRId64"B \033[K",
+                            pass + 1, global.passes, frames_in,
+                            streams->frames_out, streams->nbytes);
+                else
+                    fprintf(stderr,
+                            "\rPass %d/%d frame %4d %7lu %s (%.2f fps)\033[K",
+                            pass + 1, global.passes, frames_in,
+                            cx_time > 9999999 ? cx_time / 1000 : cx_time,
+                            cx_time > 9999999 ? "ms" : "us",
+                            usec_to_fps(cx_time, frames_in));
+
             }
             else
                 frame_avail = 0;
 
             vpx_usec_timer_start(&timer);
-
-            frame_start = (cfg.g_timebase.den * (int64_t)(frames_in - 1)
-                          * global.framerate.den) / cfg.g_timebase.num / global.framerate.num;
-            next_frame_start = (cfg.g_timebase.den * (int64_t)(frames_in)
-                                * global.framerate.den)
-                                / cfg.g_timebase.num / global.framerate.num;
-            vpx_codec_encode(&encoder, frame_avail ? &raw : NULL, frame_start,
-                             next_frame_start - frame_start,
-                             0, global.deadline);
+            FOREACH_STREAM(encode_frame(stream, &global,
+                                        frame_avail ? &raw : NULL,
+                                        frames_in));
             vpx_usec_timer_mark(&timer);
             cx_time += vpx_usec_timer_elapsed(&timer);
-            ctx_exit_on_error(&encoder, "Failed to encode frame");
 
-            if(cfg.g_pass != VPX_RC_FIRST_PASS)
-            {
-                int q;
-
-                vpx_codec_control(&encoder, VP8E_GET_LAST_QUANTIZER_64, &q);
-                ctx_exit_on_error(&encoder, "Failed to read quantizer");
-                counts[q]++;
-            }
+            FOREACH_STREAM(update_quantizer_histogram(stream));
 
             got_data = 0;
-
-            while ((pkt = vpx_codec_get_cx_data(&encoder, &iter)))
-            {
-                got_data = 1;
-
-                switch (pkt->kind)
-                {
-                case VPX_CODEC_CX_FRAME_PKT:
-                    frames_out++;
-                    fprintf(stderr, " %6luF",
-                            (unsigned long)pkt->data.frame.sz);
-
-                    update_rate_histogram(&rate_hist, &cfg, pkt);
-                    if(global.write_webm)
-                    {
-                        /* Update the hash */
-                        if(!ebml.debug)
-                            hash = murmur(pkt->data.frame.buf,
-                                          pkt->data.frame.sz, hash);
-
-                        write_webm_block(&ebml, &cfg, pkt);
-                    }
-                    else
-                    {
-                        write_ivf_frame_header(outfile, pkt);
-                        if(fwrite(pkt->data.frame.buf, 1,
-                                  pkt->data.frame.sz, outfile));
-                    }
-                    nbytes += pkt->data.raw.sz;
-                    break;
-                case VPX_CODEC_STATS_PKT:
-                    frames_out++;
-                    fprintf(stderr, " %6luS",
-                           (unsigned long)pkt->data.twopass_stats.sz);
-                    stats_write(&stats,
-                                pkt->data.twopass_stats.buf,
-                                pkt->data.twopass_stats.sz);
-                    nbytes += pkt->data.raw.sz;
-                    break;
-                case VPX_CODEC_PSNR_PKT:
-
-                    if (global.show_psnr)
-                    {
-                        int i;
-
-                        psnr_sse_total += pkt->data.psnr.sse[0];
-                        psnr_samples_total += pkt->data.psnr.samples[0];
-                        for (i = 0; i < 4; i++)
-                        {
-                            fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]);
-                            psnr_totals[i] += pkt->data.psnr.psnr[i];
-                        }
-                        psnr_count++;
-                    }
-
-                    break;
-                default:
-                    break;
-                }
-            }
+            FOREACH_STREAM(get_cx_data(stream, &global, &got_data));
 
             fflush(stdout);
         }
 
-        fprintf(stderr,
-               "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s"
-               " %7lu %s (%.2f fps)\033[K", pass + 1,
-               global.passes, frames_in, frames_out, nbytes,
-               frames_in ? (unsigned long)(nbytes * 8 / frames_in) : 0,
-               frames_in ? nbytes * 8 *(int64_t)global.framerate.num / global.framerate.den / frames_in : 0,
-               cx_time > 9999999 ? cx_time / 1000 : cx_time,
-               cx_time > 9999999 ? "ms" : "us",
-               cx_time > 0 ? (float)frames_in * 1000000.0 / (float)cx_time : 0);
+        if(stream_cnt > 1)
+            fprintf(stderr, "\n");
 
-        if ( (global.show_psnr) && (psnr_count>0) )
-        {
-            int i;
-            double ovpsnr = vp8_mse2psnr(psnr_samples_total, 255.0,
-                                         psnr_sse_total);
+        FOREACH_STREAM(fprintf(
+            stderr,
+            "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s"
+            " %7lu %s (%.2f fps)\033[K\n", pass + 1,
+            global.passes, frames_in, stream->frames_out, stream->nbytes,
+            frames_in ? (unsigned long)(stream->nbytes * 8 / frames_in) : 0,
+            frames_in ? stream->nbytes * 8
+                        * (int64_t)global.framerate.num / global.framerate.den
+                        / frames_in
+                      : 0,
+            stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time,
+            stream->cx_time > 9999999 ? "ms" : "us",
+            usec_to_fps(stream->cx_time, frames_in));
+        );
 
-            fprintf(stderr, "\nPSNR (Overall/Avg/Y/U/V)");
+        if (global.show_psnr)
+            FOREACH_STREAM(show_psnr(stream));
 
-            fprintf(stderr, " %.3lf", ovpsnr);
-            for (i = 0; i < 4; i++)
-            {
-                fprintf(stderr, " %.3lf", psnr_totals[i]/psnr_count);
-            }
-        }
-
-        vpx_codec_destroy(&encoder);
+        FOREACH_STREAM(vpx_codec_destroy(&stream->encoder));
 
         close_input_file(&input);
 
-        if(global.write_webm)
-        {
-            write_webm_file_footer(&ebml, hash);
-            free(ebml.cue_list);
-            ebml.cue_list = NULL;
-        }
-        else
-        {
-            if (!fseek(outfile, 0, SEEK_SET))
-                write_ivf_file_header(outfile, &cfg, global.codec->fourcc,
-                                      frames_out);
-        }
+        FOREACH_STREAM(close_output_file(stream, global.codec->fourcc));
 
-        fclose(outfile);
-        stats_close(&stats, global.passes-1);
-        fprintf(stderr, "\n");
+        FOREACH_STREAM(stats_close(&stream->stats, global.passes-1));
 
         if (global.pass)
             break;
     }
 
     if (global.show_q_hist_buckets)
-        show_q_histogram(counts, global.show_q_hist_buckets);
+        FOREACH_STREAM(show_q_histogram(stream->counts,
+                                        global.show_q_hist_buckets));
 
     if (global.show_rate_hist_buckets)
-        show_rate_histogram(&rate_hist, &cfg, global.show_rate_hist_buckets);
-    destroy_rate_histogram(&rate_hist);
+        FOREACH_STREAM(show_rate_histogram(&stream->rate_hist,
+                                           &stream->config.cfg,
+                                           global.show_rate_hist_buckets));
+    FOREACH_STREAM(destroy_rate_histogram(&stream->rate_hist));
 
     vpx_img_free(&raw);
     free(argv);