Fix pulsing issue with scaling

Updates the YV12_BUFFER_CONFIG structure to be crop-aware. The
exiting width/height parameters are left unchanged, storing the
width and height algined to a 16 byte boundary. The cropped
dimensions are added as new fields.

This fixes a nasty visual pulse when switching between scaled and
unscaled frame dimensions due to a mismatch between the scaling
ratio and the 16-byte aligned sizes.

Change-Id: Id4a3f6aea6b9b9ae38bdfa1b87b7eb2cfcdd57b6
diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c
index c3d6dae..15c8c0d 100644
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -67,16 +67,13 @@
 
 int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) {
   int i;
+  int aligned_width, aligned_height;
 
   vp9_de_alloc_frame_buffers(oci);
 
   /* our internal buffers are always multiples of 16 */
-  if ((width & 0xf) != 0)
-    width += 16 - (width & 0xf);
-
-  if ((height & 0xf) != 0)
-    height += 16 - (height & 0xf);
-
+  aligned_width = (width + 15) & ~15;
+  aligned_height = (height + 15) & ~15;
 
   for (i = 0; i < NUM_YV12_BUFFERS; i++) {
     oci->fb_idx_ref_cnt[i] = 0;
@@ -110,8 +107,8 @@
     return 1;
   }
 
-  oci->mb_rows = height >> 4;
-  oci->mb_cols = width >> 4;
+  oci->mb_rows = aligned_height >> 4;
+  oci->mb_cols = aligned_width >> 4;
   oci->MBs = oci->mb_rows * oci->mb_cols;
   oci->mode_info_stride = oci->mb_cols + 1;
   oci->mip = vpx_calloc((oci->mb_cols + 1) * (oci->mb_rows + 1), sizeof(MODE_INFO));
diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c
index a0867ae..f98ec44 100644
--- a/vp9/common/vp9_reconinter.c
+++ b/vp9/common/vp9_reconinter.c
@@ -20,8 +20,8 @@
 void vp9_setup_scale_factors_for_frame(struct scale_factors *scale,
                                        YV12_BUFFER_CONFIG *other,
                                        int this_w, int this_h) {
-  int other_h = other->y_height;
-  int other_w = other->y_width;
+  int other_h = other->y_crop_height;
+  int other_w = other->y_crop_width;
 
   scale->x_num = other_w;
   scale->x_den = this_w;
@@ -95,7 +95,7 @@
 
     vp9_setup_scale_factors_for_frame(&cm->active_ref_scale[i],
                                       &cm->yv12_fb[cm->active_ref_idx[i]],
-                                      cm->mb_cols * 16, cm->mb_rows * 16);
+                                      cm->Width, cm->Height);
   }
 
   if (xd->mode_info_context) {
diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c
index 572ba29..a332473 100644
--- a/vp9/decoder/vp9_decodframe.c
+++ b/vp9/decoder/vp9_decodframe.c
@@ -1367,7 +1367,7 @@
 
   /* Reset the frame pointers to the current frame size */
   vp8_yv12_realloc_frame_buffer(&pc->yv12_fb[pc->new_fb_idx],
-                                pc->mb_cols * 16, pc->mb_rows * 16,
+                                pc->Width, pc->Height,
                                 VP9BORDERINPIXELS);
 
   if (vp9_start_decode(&header_bc, data,
diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c
index 2214ac9..a89d254 100644
--- a/vp9/encoder/vp9_lookahead.c
+++ b/vp9/encoder/vp9_lookahead.c
@@ -62,10 +62,6 @@
   // Clamp the lookahead queue depth
   depth = clamp(depth, 1, MAX_LAG_BUFFERS);
 
-  // Align the buffer dimensions
-  width = (width + 15) &~15;
-  height = (height + 15) &~15;
-
   // Allocate the lookahead structures
   ctx = calloc(1, sizeof(*ctx));
   if (ctx) {
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index 19456e4..5e4b491 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -873,9 +873,6 @@
 }
 
 static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
-  int width = (cpi->oxcf.Width + 15) & ~15;
-  int height = (cpi->oxcf.Height + 15) & ~15;
-
   cpi->lookahead = vp9_lookahead_init(cpi->oxcf.Width, cpi->oxcf.Height,
                                       cpi->oxcf.lag_in_frames);
   if (!cpi->lookahead)
@@ -885,7 +882,8 @@
 #if VP9_TEMPORAL_ALT_REF
 
   if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer,
-                                  width, height, VP9BORDERINPIXELS))
+                                  cpi->oxcf.Width, cpi->oxcf.Height,
+                                  VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate altref buffer");
 
@@ -909,10 +907,7 @@
 void vp9_alloc_compressor_data(VP9_COMP *cpi) {
   VP9_COMMON *cm = &cpi->common;
 
-  int width = cm->Width;
-  int height = cm->Height;
-
-  if (vp9_alloc_frame_buffers(cm, width, height))
+  if (vp9_alloc_frame_buffers(cm, cm->Width, cm->Height))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate frame buffers");
 
@@ -920,21 +915,13 @@
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate partition data");
 
-
-  if ((width & 0xf) != 0)
-    width += 16 - (width & 0xf);
-
-  if ((height & 0xf) != 0)
-    height += 16 - (height & 0xf);
-
-
   if (vp8_yv12_alloc_frame_buffer(&cpi->last_frame_uf,
-                                  width, height, VP9BORDERINPIXELS))
+                                  cm->Width, cm->Height, VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate last frame buffer");
 
   if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source,
-                                  width, height, VP9BORDERINPIXELS))
+                                  cm->Width, cm->Height, VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to allocate scaled source buffer");
 
@@ -996,11 +983,11 @@
   VP9_COMMON *cm = &cpi->common;
 
   /* our internal buffers are always multiples of 16 */
-  int width = (cm->Width + 15) & ~15;
-  int height = (cm->Height + 15) & ~15;
+  int aligned_width = (cm->Width + 15) & ~15;
+  int aligned_height = (cm->Height + 15) & ~15;
 
-  cm->mb_rows = height >> 4;
-  cm->mb_cols = width >> 4;
+  cm->mb_rows = aligned_height >> 4;
+  cm->mb_cols = aligned_width >> 4;
   cm->MBs = cm->mb_rows * cm->mb_cols;
   cm->mode_info_stride = cm->mb_cols + 1;
   memset(cm->mip, 0,
@@ -1013,12 +1000,12 @@
 
   /* Update size of buffers local to this frame */
   if (vp8_yv12_realloc_frame_buffer(&cpi->last_frame_uf,
-                                    width, height, VP9BORDERINPIXELS))
+                                    cm->Width, cm->Height, VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to reallocate last frame buffer");
 
   if (vp8_yv12_realloc_frame_buffer(&cpi->scaled_source,
-                                    width, height, VP9BORDERINPIXELS))
+                                    cm->Width, cm->Height, VP9BORDERINPIXELS))
     vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
                        "Failed to reallocate scaled source buffer");
 
@@ -1315,9 +1302,6 @@
   cm->Width       = cpi->oxcf.Width;
   cm->Height      = cpi->oxcf.Height;
 
-  cm->horiz_scale  = cpi->horiz_scale;
-  cm->vert_scale   = cpi->vert_scale;
-
   // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs)
   if (cpi->oxcf.Sharpness > 7)
     cpi->oxcf.Sharpness = 7;
@@ -2223,10 +2207,10 @@
 
 static void scale_and_extend_frame(YV12_BUFFER_CONFIG *src_fb,
                                    YV12_BUFFER_CONFIG *dst_fb) {
-  const int in_w = src_fb->y_width;
-  const int in_h = src_fb->y_height;
-  const int out_w = dst_fb->y_width;
-  const int out_h = dst_fb->y_height;
+  const int in_w = src_fb->y_crop_width;
+  const int in_h = src_fb->y_crop_height;
+  const int out_w = dst_fb->y_crop_width;
+  const int out_h = dst_fb->y_crop_height;
   int x, y;
 
   for (y = 0; y < out_h; y += 16) {
@@ -2628,12 +2612,12 @@
   for (i = 0; i < 3; i++) {
     YV12_BUFFER_CONFIG *ref = &cm->yv12_fb[cm->ref_frame_map[i]];
 
-    if (ref->y_width != cm->mb_cols * 16 || ref->y_height != cm->mb_rows * 16) {
+    if (ref->y_crop_width != cm->Width ||
+        ref->y_crop_height != cm->Height) {
       int new_fb = get_free_fb(cm);
 
       vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[new_fb],
-                                    cm->mb_cols * 16,
-                                    cm->mb_rows * 16,
+                                    cm->Width, cm->Height,
                                     VP9BORDERINPIXELS);
       scale_and_extend_frame(ref, &cm->yv12_fb[new_fb]);
       cpi->scaled_ref_idx[i] = new_fb;
@@ -3912,7 +3896,7 @@
 
   /* Reset the frame pointers to the current frame size */
   vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[cm->new_fb_idx],
-                                cm->mb_cols * 16, cm->mb_rows * 16,
+                                cm->Width, cm->Height,
                                 VP9BORDERINPIXELS);
 
   vp9_setup_interp_filters(&cpi->mb.e_mbd, DEFAULT_INTERP_FILTER, cm);
diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h
index 300e128..a7a07b3 100644
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -545,8 +545,6 @@
   int goldfreq;
   int auto_worst_q;
   int cpu_used;
-  int horiz_scale;
-  int vert_scale;
   int pass;
 
   vp9_prob last_skip_false_probs[3][MBSKIP_CONTEXTS];
diff --git a/vp9/encoder/vp9_picklpf.c b/vp9/encoder/vp9_picklpf.c
index 6f93335..d80ea02 100644
--- a/vp9/encoder/vp9_picklpf.c
+++ b/vp9/encoder/vp9_picklpf.c
@@ -247,7 +247,7 @@
   int Bias = 0;                       // Bias against raising loop filter and in favour of lowering it
 
   //  Make a copy of the unfiltered / processed recon buffer
-  vp8_yv12_copy_frame(cm->frame_to_show, &cpi->last_frame_uf);
+  vp8_yv12_copy_y(cm->frame_to_show, &cpi->last_frame_uf);
 
   if (cm->frame_type == KEY_FRAME)
     cm->sharpness_level = 0;
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 3004d6b..387e325 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -3444,9 +3444,11 @@
 
   // Further refinement that is encode side only to test the top few candidates
   // in full and choose the best as the centre point for subsequent searches.
-  mv_pred(cpi, x, yv12_mb[frame_type].y_buffer, yv12->y_stride,
-          frame_type, block_size);
-
+  // The current implementation doesn't support scaling.
+  if (scale[frame_type].x_num == scale[frame_type].x_den &&
+      scale[frame_type].y_num == scale[frame_type].y_den)
+    mv_pred(cpi, x, yv12_mb[frame_type].y_buffer, yv12->y_stride,
+            frame_type, block_size);
 }
 
 static void model_rd_from_var_lapndz(int var, int n, int qstep,
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index a6cd1c0..7bfca55 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -459,8 +459,8 @@
   // Setup scaling factors. Scaling on each of the arnr frames is not supported
   vp9_setup_scale_factors_for_frame(&cpi->mb.e_mbd.scale_factor[0],
       &cpi->common.yv12_fb[cpi->common.new_fb_idx],
-      16 * cpi->common.mb_cols,
-      16 * cpi->common.mb_rows);
+      cpi->common.Width,
+      cpi->common.Height);
   cpi->mb.e_mbd.scale_factor_uv[0] = cpi->mb.e_mbd.scale_factor[0];
 
   // Setup frame pointers, NULL indicates frame not included in filter
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index c0828ac..1eeec6b 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -545,6 +545,8 @@
   yv12->u_buffer = img->planes[VPX_PLANE_U];
   yv12->v_buffer = img->planes[VPX_PLANE_V];
 
+  yv12->y_crop_width  = img->d_w;
+  yv12->y_crop_height = img->d_h;
   yv12->y_width  = img->d_w;
   yv12->y_height = img->d_h;
   yv12->uv_width = (1 + yv12->y_width) / 2;
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 655d25b..66c89b5 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -584,6 +584,8 @@
   yv12->u_buffer = img->planes[VPX_PLANE_U];
   yv12->v_buffer = img->planes[VPX_PLANE_V];
 
+  yv12->y_crop_width  = img->d_w;
+  yv12->y_crop_height = img->d_h;
   yv12->y_width  = img->d_w;
   yv12->y_height = img->d_h;
   yv12->uv_width = yv12->y_width / 2;
diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c
index 267d55f..fc7f828 100644
--- a/vpx_scale/generic/yv12config.c
+++ b/vpx_scale/generic/yv12config.c
@@ -38,10 +38,12 @@
 int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
                                   int width, int height, int border) {
   if (ybf) {
-    int y_stride = ((width + 2 * border) + 31) & ~31;
-    int yplane_size = (height + 2 * border) * y_stride;
-    int uv_width = width >> 1;
-    int uv_height = height >> 1;
+    int aligned_width = (width + 15) & ~15;
+    int aligned_height = (height + 15) & ~15;
+    int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
+    int yplane_size = (aligned_height + 2 * border) * y_stride;
+    int uv_width = aligned_width >> 1;
+    int uv_height = aligned_height >> 1;
     /** There is currently a bunch of code which assumes
       *  uv_stride == y_stride/2, so enforce this here. */
     int uv_stride = y_stride >> 1;
@@ -56,17 +58,18 @@
     if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size)
       return -1;
 
-    /** Only support allocating buffers that have a height and width that
-      *  are multiples of 16, and a border that's a multiple of 32.
-      * The border restriction is required to get 16-byte alignment of the
-      *  start of the chroma rows without intoducing an arbitrary gap
-      *  between planes, which would break the semantics of things like
-      *  vpx_img_set_rect(). */
-    if ((width & 0xf) | (height & 0xf) | (border & 0x1f))
+    /* Only support allocating buffers that have a border that's a multiple
+     * of 32. The border restriction is required to get 16-byte alignment of
+     * the start of the chroma rows without intoducing an arbitrary gap
+     * between planes, which would break the semantics of things like
+     * vpx_img_set_rect(). */
+    if (border & 0x1f)
       return -3;
 
-    ybf->y_width  = width;
-    ybf->y_height = height;
+    ybf->y_crop_width = width;
+    ybf->y_crop_height = height;
+    ybf->y_width  = aligned_width;
+    ybf->y_height = aligned_height;
     ybf->y_stride = y_stride;
 
     ybf->uv_width = uv_width;
diff --git a/vpx_scale/generic/yv12extend.c b/vpx_scale/generic/yv12extend.c
index d733bd4..49d7e8e 100644
--- a/vpx_scale/generic/yv12extend.c
+++ b/vpx_scale/generic/yv12extend.c
@@ -20,180 +20,81 @@
 /****************************************************************************
  *
  ****************************************************************************/
+static void extend_plane(uint8_t *s,       /* source */
+                         int sp,           /* source pitch */
+                         int w,            /* width */
+                         int h,            /* height */
+                         int et,           /* extend top border */
+                         int el,           /* extend left border */
+                         int eb,           /* extend bottom border */
+                         int er) {         /* extend right border */
+  int i;
+  uint8_t *src_ptr1, *src_ptr2;
+  uint8_t *dest_ptr1, *dest_ptr2;
+  int linesize;
+
+  /* copy the left and right most columns out */
+  src_ptr1 = s;
+  src_ptr2 = s + w - 1;
+  dest_ptr1 = s - el;
+  dest_ptr2 = s + w;
+
+  for (i = 0; i < h; i++) {
+    vpx_memset(dest_ptr1, src_ptr1[0], el);
+    vpx_memset(dest_ptr2, src_ptr2[0], er);
+    src_ptr1  += sp;
+    src_ptr2  += sp;
+    dest_ptr1 += sp;
+    dest_ptr2 += sp;
+  }
+
+  /* Now copy the top and bottom lines into each line of the respective
+   * borders
+   */
+  src_ptr1 = s - el;
+  src_ptr2 = s + sp * (h - 1) - el;
+  dest_ptr1 = s + sp * (-et) - el;
+  dest_ptr2 = s + sp * (h) - el;
+  linesize = el + er + w;
+
+  for (i = 0; i < et; i++) {
+    vpx_memcpy(dest_ptr1, src_ptr1, linesize);
+    dest_ptr1 += sp;
+  }
+
+  for (i = 0; i < eb; i++) {
+    vpx_memcpy(dest_ptr2, src_ptr2, linesize);
+    dest_ptr2 += sp;
+  }
+}
+
 void
 vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) {
-  int i;
-  unsigned char *src_ptr1, *src_ptr2;
-  unsigned char *dest_ptr1, *dest_ptr2;
+  assert(ybf->y_height - ybf->y_crop_height < 16);
+  assert(ybf->y_width - ybf->y_crop_width < 16);
+  assert(ybf->y_height - ybf->y_crop_height >= 0);
+  assert(ybf->y_width - ybf->y_crop_width >= 0);
 
-  unsigned int Border;
-  int plane_stride;
-  int plane_height;
-  int plane_width;
+  extend_plane(ybf->y_buffer, ybf->y_stride,
+               ybf->y_crop_width, ybf->y_crop_height,
+               ybf->border, ybf->border,
+               ybf->border + ybf->y_height - ybf->y_crop_height,
+               ybf->border + ybf->y_width - ybf->y_crop_width);
 
-  /***********/
-  /* Y Plane */
-  /***********/
-  Border = ybf->border;
-  plane_stride = ybf->y_stride;
-  plane_height = ybf->y_height;
-  plane_width = ybf->y_width;
+  extend_plane(ybf->u_buffer, ybf->uv_stride,
+               (ybf->y_crop_width + 1) / 2, (ybf->y_crop_height + 1) / 2,
+               ybf->border / 2, ybf->border / 2,
+               (ybf->border + ybf->y_height - ybf->y_crop_height + 1) / 2,
+               (ybf->border + ybf->y_width - ybf->y_crop_width + 1) / 2);
 
-  /* copy the left and right most columns out */
-  src_ptr1 = ybf->y_buffer;
-  src_ptr2 = src_ptr1 + plane_width - 1;
-  dest_ptr1 = src_ptr1 - Border;
-  dest_ptr2 = src_ptr2 + 1;
-
-  for (i = 0; i < plane_height; i++) {
-    vpx_memset(dest_ptr1, src_ptr1[0], Border);
-    vpx_memset(dest_ptr2, src_ptr2[0], Border);
-    src_ptr1  += plane_stride;
-    src_ptr2  += plane_stride;
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  /* Now copy the top and bottom source lines into each line of the respective borders */
-  src_ptr1 = ybf->y_buffer - Border;
-  src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
-  dest_ptr1 = src_ptr1 - (Border * plane_stride);
-  dest_ptr2 = src_ptr2 + plane_stride;
-
-  for (i = 0; i < (int)Border; i++) {
-    vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
-    vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-
-  /***********/
-  /* U Plane */
-  /***********/
-  plane_stride = ybf->uv_stride;
-  plane_height = ybf->uv_height;
-  plane_width = ybf->uv_width;
-  Border /= 2;
-
-  /* copy the left and right most columns out */
-  src_ptr1 = ybf->u_buffer;
-  src_ptr2 = src_ptr1 + plane_width - 1;
-  dest_ptr1 = src_ptr1 - Border;
-  dest_ptr2 = src_ptr2 + 1;
-
-  for (i = 0; i < plane_height; i++) {
-    vpx_memset(dest_ptr1, src_ptr1[0], Border);
-    vpx_memset(dest_ptr2, src_ptr2[0], Border);
-    src_ptr1  += plane_stride;
-    src_ptr2  += plane_stride;
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  /* Now copy the top and bottom source lines into each line of the respective borders */
-  src_ptr1 = ybf->u_buffer - Border;
-  src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
-  dest_ptr1 = src_ptr1 - (Border * plane_stride);
-  dest_ptr2 = src_ptr2 + plane_stride;
-
-  for (i = 0; i < (int)(Border); i++) {
-    vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
-    vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  /***********/
-  /* V Plane */
-  /***********/
-
-  /* copy the left and right most columns out */
-  src_ptr1 = ybf->v_buffer;
-  src_ptr2 = src_ptr1 + plane_width - 1;
-  dest_ptr1 = src_ptr1 - Border;
-  dest_ptr2 = src_ptr2 + 1;
-
-  for (i = 0; i < plane_height; i++) {
-    vpx_memset(dest_ptr1, src_ptr1[0], Border);
-    vpx_memset(dest_ptr2, src_ptr2[0], Border);
-    src_ptr1  += plane_stride;
-    src_ptr2  += plane_stride;
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  /* Now copy the top and bottom source lines into each line of the respective borders */
-  src_ptr1 = ybf->v_buffer - Border;
-  src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
-  dest_ptr1 = src_ptr1 - (Border * plane_stride);
-  dest_ptr2 = src_ptr2 + plane_stride;
-
-  for (i = 0; i < (int)(Border); i++) {
-    vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
-    vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
+  extend_plane(ybf->v_buffer, ybf->uv_stride,
+               (ybf->y_crop_width + 1) / 2, (ybf->y_crop_height + 1) / 2,
+               ybf->border / 2, ybf->border / 2,
+               (ybf->border + ybf->y_height - ybf->y_crop_height + 1) / 2,
+               (ybf->border + ybf->y_width - ybf->y_crop_width + 1) / 2);
 }
 
 
-static void
-extend_frame_borders_yonly_c(YV12_BUFFER_CONFIG *ybf) {
-  int i;
-  unsigned char *src_ptr1, *src_ptr2;
-  unsigned char *dest_ptr1, *dest_ptr2;
-
-  unsigned int Border;
-  int plane_stride;
-  int plane_height;
-  int plane_width;
-
-  /***********/
-  /* Y Plane */
-  /***********/
-  Border = ybf->border;
-  plane_stride = ybf->y_stride;
-  plane_height = ybf->y_height;
-  plane_width = ybf->y_width;
-
-  /* copy the left and right most columns out */
-  src_ptr1 = ybf->y_buffer;
-  src_ptr2 = src_ptr1 + plane_width - 1;
-  dest_ptr1 = src_ptr1 - Border;
-  dest_ptr2 = src_ptr2 + 1;
-
-  for (i = 0; i < plane_height; i++) {
-    vpx_memset(dest_ptr1, src_ptr1[0], Border);
-    vpx_memset(dest_ptr2, src_ptr2[0], Border);
-    src_ptr1  += plane_stride;
-    src_ptr2  += plane_stride;
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  /* Now copy the top and bottom source lines into each line of the respective borders */
-  src_ptr1 = ybf->y_buffer - Border;
-  src_ptr2 = src_ptr1 + (plane_height * plane_stride) - plane_stride;
-  dest_ptr1 = src_ptr1 - (Border * plane_stride);
-  dest_ptr2 = src_ptr2 + plane_stride;
-
-  for (i = 0; i < (int)Border; i++) {
-    vpx_memcpy(dest_ptr1, src_ptr1, plane_stride);
-    vpx_memcpy(dest_ptr2, src_ptr2, plane_stride);
-    dest_ptr1 += plane_stride;
-    dest_ptr2 += plane_stride;
-  }
-
-  plane_stride /= 2;
-  plane_height /= 2;
-  plane_width /= 2;
-  Border /= 2;
-
-}
-
-
-
 /****************************************************************************
  *
  *  ROUTINE       : vp8_yv12_copy_frame
diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h
index 45e57f4..14b6e27 100644
--- a/vpx_scale/yv12config.h
+++ b/vpx_scale/yv12config.h
@@ -42,6 +42,8 @@
   typedef struct yv12_buffer_config {
     int   y_width;
     int   y_height;
+    int   y_crop_width;
+    int   y_crop_height;
     int   y_stride;
     /*    int   yinternal_width; */
 
diff --git a/vpxdec.c b/vpxdec.c
index 30196ec..287e796 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -711,7 +711,7 @@
   struct input_ctx        input = {0};
   int                     frames_corrupted = 0;
   int                     dec_flags = 0;
-  int                     do_scale;
+  int                     do_scale = 0;
   int                     stream_w = 0, stream_h = 0;
   vpx_image_t             *scaled_img = NULL;