Merge "Fix the transform type selection in 4x4 partition" into experimental
diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c
index e521a69..e7303f1 100644
--- a/vp9/common/vp9_reconinter.c
+++ b/vp9/common/vp9_reconinter.c
@@ -492,3 +492,18 @@
   vp9_build_inter_predictors_sbuv(xd, mb_row, mb_col,
                                   BLOCK_SIZE_MB16X16);
 }
+
+// TODO(dkovalev: find better place for this function)
+void vp9_setup_scale_factors(VP9_COMMON *cm, int i) {
+  const int ref = cm->active_ref_idx[i];
+  struct scale_factors *const sf = &cm->active_ref_scale[i];
+  if (ref >= NUM_YV12_BUFFERS) {
+    memset(sf, 0, sizeof(*sf));
+  } else {
+    YV12_BUFFER_CONFIG *const fb = &cm->yv12_fb[ref];
+    vp9_setup_scale_factors_for_frame(sf,
+                                      fb->y_crop_width, fb->y_crop_height,
+                                      cm->width, cm->height);
+  }
+}
+
diff --git a/vp9/common/vp9_reconinter.h b/vp9/common/vp9_reconinter.h
index 885e1de..8f76195 100644
--- a/vp9/common/vp9_reconinter.h
+++ b/vp9/common/vp9_reconinter.h
@@ -122,4 +122,6 @@
   xd->scale_factor_uv[1] = xd->scale_factor[1];
 }
 
+void vp9_setup_scale_factors(VP9_COMMON *cm, int i);
+
 #endif  // VP9_COMMON_VP9_RECONINTER_H_
diff --git a/vp9/common/vp9_reconintra.c b/vp9/common/vp9_reconintra.c
index 9e580c7..ea4805f 100644
--- a/vp9/common/vp9_reconintra.c
+++ b/vp9/common/vp9_reconintra.c
@@ -378,19 +378,21 @@
 
 void vp9_build_intra_predictors_sbuv_s(MACROBLOCKD *xd,
                                        BLOCK_SIZE_TYPE bsize) {
-  const int bwl = b_width_log2(bsize), bw = 2 << bwl;
-  const int bhl = b_height_log2(bsize), bh = 2 << bhl;
+  int p;
 
-  vp9_build_intra_predictors(xd->plane[1].dst.buf, xd->plane[1].dst.stride,
-                             xd->plane[1].dst.buf, xd->plane[1].dst.stride,
-                             xd->mode_info_context->mbmi.uv_mode,
-                             bw, bh, xd->up_available,
-                             xd->left_available, 0 /*xd->right_available*/);
-  vp9_build_intra_predictors(xd->plane[2].dst.buf, xd->plane[1].dst.stride,
-                             xd->plane[2].dst.buf, xd->plane[1].dst.stride,
-                             xd->mode_info_context->mbmi.uv_mode,
-                             bw, bh, xd->up_available,
-                             xd->left_available, 0 /*xd->right_available*/);
+  for (p = 1; p < MAX_MB_PLANE; p++) {
+    const struct macroblockd_plane* const pd = &xd->plane[p];
+    const int bwl = b_width_log2(bsize) - pd->subsampling_x;
+    const int bw = 4 << bwl;
+    const int bhl = b_height_log2(bsize) - pd->subsampling_y;
+    const int bh = 4 << bhl;
+
+    vp9_build_intra_predictors(pd->dst.buf, pd->dst.stride,
+                               pd->dst.buf, pd->dst.stride,
+                               xd->mode_info_context->mbmi.uv_mode,
+                               bw, bh, xd->up_available,
+                               xd->left_available, 0 /*xd->right_available*/);
+  }
 }
 
 void vp9_intra4x4_predict(MACROBLOCKD *xd,
diff --git a/vp9/common/vp9_seg_common.c b/vp9/common/vp9_seg_common.c
index 02b7053..e5511a1 100644
--- a/vp9/common/vp9_seg_common.c
+++ b/vp9/common/vp9_seg_common.c
@@ -89,7 +89,7 @@
 #if CONFIG_IMPLICIT_SEGMENTATION
 // This function defines an implicit segmentation for the next frame based
 // on predcition and transform decisions in the current frame.
-// For test purposes at the moment only TX size is used.
+// For test purposes at the moment it uses ref frame and prediction size
 void vp9_implicit_segment_map_update(VP9_COMMON * cm) {
   int row, col;
   MODE_INFO *mi, *mi_ptr = cm->mi;
@@ -97,9 +97,66 @@
 
   for (row = 0; row < cm->mb_rows; row++) {
     mi = mi_ptr;
-    // Experimental use of tx size to define implicit segmentation
+
     for (col = 0; col < cm->mb_cols; ++col, ++mi) {
-      map_ptr[col] = 1 + mi->mbmi.txfm_size;
+      // Inter prediction
+      if (mi->mbmi.ref_frame != INTRA_FRAME) {
+        // Zero motion and prediction block size >= 16
+        if ((mi->mbmi.sb_type >= BLOCK_SIZE_MB16X16) &&
+            (mi->mbmi.mv[0].as_int == 0))
+          map_ptr[col] = 1;
+        else if (mi->mbmi.sb_type >= BLOCK_SIZE_SB32X32)
+          map_ptr[col] = 2;
+        else if (mi->mbmi.sb_type >= BLOCK_SIZE_MB16X16)
+          map_ptr[col] = 3;
+        else
+          map_ptr[col] = 6;
+
+      // Intra prediction
+      } else {
+        if (mi->mbmi.sb_type >= BLOCK_SIZE_SB32X32)
+          map_ptr[col] = 4;
+        else if (mi->mbmi.sb_type >= BLOCK_SIZE_MB16X16)
+          map_ptr[col] = 5;
+        else
+          map_ptr[col] = 7;
+      }
+    }
+    mi_ptr += cm->mode_info_stride;
+    map_ptr += cm->mb_cols;
+  }
+}
+
+// This function defines an implicit segmentation for the next frame based
+// on predcition and transform decisions in the current frame.
+// For test purposes at the moment only TX size is used.
+void vp9_implicit_segment_map_update_tx(VP9_COMMON * cm) {
+  int row, col;
+  MODE_INFO *mi, *mi_ptr = cm->mi;
+  unsigned char * map_ptr = cm->last_frame_seg_map;
+
+  for (row = 0; row < cm->mb_rows; row++) {
+    mi = mi_ptr;
+    for (col = 0; col < cm->mb_cols; ++col, ++mi) {
+      // Intra modes
+      if (mi->mbmi.ref_frame == INTRA_FRAME) {
+        if (mi->mbmi.txfm_size == TX_4X4)
+          map_ptr[col] = 7;
+        else if (mi->mbmi.txfm_size <= TX_16X16)
+          map_ptr[col] = 5;
+        else
+          map_ptr[col] = 4;
+      } else {
+        // Inter Modes
+        if (mi->mbmi.txfm_size == TX_4X4)
+          map_ptr[col] = 6;
+        else if (mi->mbmi.txfm_size == TX_8X8)
+          map_ptr[col] = 3;
+        else if (mi->mbmi.txfm_size == TX_16X16)
+          map_ptr[col] = 2;
+        else
+          map_ptr[col] = 1;
+      }
     }
     mi_ptr += cm->mode_info_stride;
     map_ptr += cm->mb_cols;
@@ -107,6 +164,7 @@
 }
 #endif
 
+
 const vp9_tree_index vp9_segment_tree[14] = {
   2,  4,  6,  8, 10, 12,
   0, -1, -2, -3, -4, -5, -6, -7
diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c
index 6a79c6c..2e233c3 100644
--- a/vp9/decoder/vp9_decodframe.c
+++ b/vp9/decoder/vp9_decodframe.c
@@ -1021,23 +1021,13 @@
     // Select active reference frames and calculate scaling factors
     for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i) {
       const int ref = vp9_read_literal(&header_bc, NUM_REF_FRAMES_LG2);
-      const int mapped_ref = pc->ref_frame_map[ref];
-      YV12_BUFFER_CONFIG *const fb = &pc->yv12_fb[mapped_ref];
-      struct scale_factors *const sf = &pc->active_ref_scale[i];
-
-      pc->active_ref_idx[i] = mapped_ref;
-      if (mapped_ref >= NUM_YV12_BUFFERS)
-        memset(sf, 0, sizeof(*sf));
-      else
-        vp9_setup_scale_factors_for_frame(sf,
-                                          fb->y_crop_width, fb->y_crop_height,
-                                          pc->width, pc->height);
+      pc->active_ref_idx[i] = pc->ref_frame_map[ref];
+      vp9_setup_scale_factors(pc, i);
     }
 
     // Read the sign bias for each reference frame buffer.
-    for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i) {
+    for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i)
       pc->ref_frame_sign_bias[i + 1] = vp9_read_bit(&header_bc);
-    }
 
     xd->allow_high_precision_mv = vp9_read_bit(&header_bc);
     pc->mcomp_filter_type = read_mcomp_filter_type(&header_bc);
diff --git a/vp9/decoder/vp9_onyxd_if.c b/vp9/decoder/vp9_onyxd_if.c
index c0ce311..6a55e8f 100644
--- a/vp9/decoder/vp9_onyxd_if.c
+++ b/vp9/decoder/vp9_onyxd_if.c
@@ -352,7 +352,8 @@
       vp9_loop_filter_frame(cm, &pbi->mb, cm->filter_level, 0,
                             cm->dering_enabled);
     }
-    vp8_yv12_extend_frame_borders(cm->frame_to_show);
+    vp9_extend_frame_borders(cm->frame_to_show,
+                             cm->subsampling_x, cm->subsampling_y);
   }
 
 #if WRITE_RECON_BUFFER == 1
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index ddcf849..367ebec 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -522,6 +522,8 @@
       xd->plane[2].dst.buf = new_yv12->v_buffer + recon_uvoffset;
       xd->left_available = (mb_col != 0);
 
+      xd->mode_info_context->mbmi.sb_type = BLOCK_SIZE_MB16X16;
+
       // do intra 16x16 prediction
       this_error = vp9_encode_intra(cpi, x, use_dc_pred);
 
@@ -768,7 +770,7 @@
   // swap frame pointers so last frame refers to the frame we just compressed
   swap_yv12(lst_yv12, new_yv12);
 
-  vp8_yv12_extend_frame_borders(lst_yv12);
+  vp9_extend_frame_borders(lst_yv12, cm->subsampling_x, cm->subsampling_y);
 
   // Special case for the first frame. Copy into the GF buffer as a second reference.
   if (cm->current_video_frame == 0)
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index d78373f..67d1b67 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -487,12 +487,14 @@
 }
 
 #if CONFIG_IMPLICIT_SEGMENTATION
-static void configure_implicit_segmentation(VP9_COMP *cpi) {
+static double implict_seg_q_modifiers[MAX_MB_SEGMENTS] =
+  {1.0, 0.95, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
+static void configure_implicit_segmentation(VP9_COMP *cpi, int frame_qindex) {
   VP9_COMMON *cm = &cpi->common;
   MACROBLOCKD *xd = &cpi->mb.e_mbd;
   int i;
   int qi_delta;
-  double q_target = cpi->active_worst_quality * 1.10;
+  double q_baseline = vp9_convert_qindex_to_q(frame_qindex);
 
   // Set the flags to allow implicit segment update but disallow explicit update
   xd->segmentation_enabled = 1;
@@ -507,13 +509,19 @@
     // Clear down the segment features.
     vp9_clearall_segfeatures(xd);
 
+    xd->update_mb_segmentation_data = 0;
+
+  // Update the segment data if it is an arf or non overlay gf.
+  } else if (cpi->refresh_alt_ref_frame ||
+             (cpi->refresh_golden_frame && !cpi->is_src_frame_alt_ref)) {
     xd->update_mb_segmentation_data = 1;
 
     // Enable use of q deltas on segments 1 and up
+    // Segment 0 is treated as a neutral segment with no changes
     for (i = 1; i < MAX_MB_SEGMENTS; ++i) {
-      qi_delta = compute_qdelta(cpi, cpi->active_worst_quality, q_target);
+      qi_delta = compute_qdelta(cpi, q_baseline,
+                                implict_seg_q_modifiers[i] * q_baseline);
       vp9_set_segdata(xd, i, SEG_LVL_ALT_Q, qi_delta);
-      q_target *= 0.95;
       vp9_enable_segfeature(xd, i, SEG_LVL_ALT_Q);
     }
 
@@ -728,7 +736,7 @@
 #if CONFIG_IMPLICIT_SEGMENTATION
   sf->static_segmentation = 0;
 #else
-  sf->static_segmentation = 1;
+  sf->static_segmentation = 0;
 #endif
 #endif
   sf->splitmode_breakout = 0;
@@ -747,7 +755,7 @@
 #if CONFIG_IMPLICIT_SEGMENTATION
   sf->static_segmentation = 0;
 #else
-  sf->static_segmentation = 1;
+  sf->static_segmentation = 0;
 #endif
 #endif
       sf->splitmode_breakout = 1;
@@ -2439,7 +2447,8 @@
                           cm->dering_enabled);
   }
 
-  vp8_yv12_extend_frame_borders(cm->frame_to_show);
+  vp9_extend_frame_borders(cm->frame_to_show,
+                           cm->subsampling_x, cm->subsampling_y);
 
 }
 
@@ -2944,13 +2953,13 @@
         cpi->common.frame_context_idx = cpi->refresh_alt_ref_frame;
         vp9_setup_inter_frame(cpi);
       }
+    }
 
 #if CONFIG_IMPLICIT_SEGMENTATION
-      if (!cm->error_resilient_mode && !cpi->sf.static_segmentation) {
-        configure_implicit_segmentation(cpi);
-      }
-#endif
+    if (!cm->error_resilient_mode && !cpi->sf.static_segmentation) {
+      configure_implicit_segmentation(cpi, q);
     }
+#endif
 
     // transform / motion compensation build reconstruction frame
 #if CONFIG_MODELCOEFPROB
@@ -3860,16 +3869,8 @@
                            VP9BORDERINPIXELS);
 
   // Calculate scaling factors for each of the 3 available references
-  for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i) {
-    if (cm->active_ref_idx[i] >= NUM_YV12_BUFFERS) {
-      memset(&cm->active_ref_scale[i], 0, sizeof(cm->active_ref_scale[i]));
-    } else {
-      YV12_BUFFER_CONFIG *fb = &cm->yv12_fb[cm->active_ref_idx[i]];
-      vp9_setup_scale_factors_for_frame(&cm->active_ref_scale[i],
-                                        fb->y_crop_width, fb->y_crop_height,
-                                        cm->width, cm->height);
-    }
-  }
+  for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i)
+    vp9_setup_scale_factors(cm, i);
 
   vp9_setup_interp_filters(&cpi->mb.e_mbd, DEFAULT_INTERP_FILTER, cm);
 
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 45609da..9326165 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -543,31 +543,6 @@
   return VPX_CODEC_OK;
 }
 
-static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
-                                       YV12_BUFFER_CONFIG  *yv12) {
-  vpx_codec_err_t        res = VPX_CODEC_OK;
-  yv12->y_buffer = img->planes[VPX_PLANE_Y];
-  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 = img->x_chroma_shift == 1 ? (1 + yv12->y_width) / 2
-                                            : yv12->y_width;
-  yv12->uv_height = img->y_chroma_shift == 1 ? (1 + yv12->y_height) / 2
-                                             : yv12->y_height;
-
-  yv12->y_stride = img->stride[VPX_PLANE_Y];
-  yv12->uv_stride = img->stride[VPX_PLANE_U];
-
-  yv12->border  = (img->stride[VPX_PLANE_Y] - img->w) / 2;
-  yv12->clrtype = REG_YUV;
-  return res;
-}
-
 static void pick_quickcompress_mode(vpx_codec_alg_priv_t  *ctx,
                                     unsigned long          duration,
                                     unsigned long          deadline) {
diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c
index 85022c9..811cea7 100644
--- a/vp9/vp9_dx_iface.c
+++ b/vp9/vp9_dx_iface.c
@@ -578,30 +578,6 @@
   return res;
 }
 
-static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
-                                       YV12_BUFFER_CONFIG  *yv12) {
-  vpx_codec_err_t        res = VPX_CODEC_OK;
-  yv12->y_buffer = img->planes[VPX_PLANE_Y];
-  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;
-  yv12->uv_height = yv12->y_height / 2;
-
-  yv12->y_stride = img->stride[VPX_PLANE_Y];
-  yv12->uv_stride = img->stride[VPX_PLANE_U];
-
-  yv12->border  = (img->stride[VPX_PLANE_Y] - img->d_w) / 2;
-  yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 ||
-                   img->fmt == VPX_IMG_FMT_VPXYV12);
-
-  return res;
-}
-
 
 static vpx_codec_err_t vp9_set_reference(vpx_codec_alg_priv_t *ctx,
                                          int ctr_id,
diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h
index 96de5f5..84b4d39 100644
--- a/vp9/vp9_iface_common.h
+++ b/vp9/vp9_iface_common.h
@@ -37,11 +37,11 @@
   img->planes[VPX_PLANE_Y] = yv12->y_buffer;
   img->planes[VPX_PLANE_U] = yv12->u_buffer;
   img->planes[VPX_PLANE_V] = yv12->v_buffer;
-  img->planes[VPX_PLANE_ALPHA] = NULL;
+  img->planes[VPX_PLANE_ALPHA] = yv12->alpha_buffer;
   img->stride[VPX_PLANE_Y] = yv12->y_stride;
   img->stride[VPX_PLANE_U] = yv12->uv_stride;
   img->stride[VPX_PLANE_V] = yv12->uv_stride;
-  img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
+  img->stride[VPX_PLANE_ALPHA] = yv12->alpha_stride;
   img->bps = bps;
   img->user_priv = user_priv;
   img->img_data = yv12->buffer_alloc;
@@ -49,4 +49,34 @@
   img->self_allocd = 0;
 }
 
+static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img,
+                                       YV12_BUFFER_CONFIG *yv12) {
+  yv12->y_buffer = img->planes[VPX_PLANE_Y];
+  yv12->u_buffer = img->planes[VPX_PLANE_U];
+  yv12->v_buffer = img->planes[VPX_PLANE_V];
+  yv12->alpha_buffer = img->planes[VPX_PLANE_ALPHA];
+
+  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 = img->x_chroma_shift == 1 ? (1 + yv12->y_width) / 2
+                                            : yv12->y_width;
+  yv12->uv_height = img->y_chroma_shift == 1 ? (1 + yv12->y_height) / 2
+                                             : yv12->y_height;
+
+  yv12->alpha_width = yv12->alpha_buffer ? img->d_w : 0;
+  yv12->alpha_height = yv12->alpha_buffer ? img->d_h : 0;
+
+  yv12->y_stride = img->stride[VPX_PLANE_Y];
+  yv12->uv_stride = img->stride[VPX_PLANE_U];
+  yv12->alpha_stride = yv12->alpha_buffer ? img->stride[VPX_PLANE_ALPHA] : 0;
+
+  yv12->border  = (img->stride[VPX_PLANE_Y] - img->w) / 2;
+  yv12->clrtype = REG_YUV;
+
+  return VPX_CODEC_OK;
+}
+
 #endif  // VP9_VP9_IFACE_COMMON_H_
diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c
index cd66f00..99e3543 100644
--- a/vpx_scale/generic/yv12config.c
+++ b/vpx_scale/generic/yv12config.c
@@ -76,12 +76,17 @@
     ybf->uv_height = uv_height;
     ybf->uv_stride = uv_stride;
 
+    ybf->alpha_width = 0;
+    ybf->alpha_height = 0;
+    ybf->alpha_stride = 0;
+
     ybf->border = border;
     ybf->frame_size = frame_size;
 
     ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border;
     ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2  * uv_stride) + border / 2;
     ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2  * uv_stride) + border / 2;
+    ybf->alpha_buffer = NULL;
 
     ybf->corrupted = 0; /* assume not currupted by errors */
     return 0;
diff --git a/vpx_scale/generic/yv12extend.c b/vpx_scale/generic/yv12extend.c
index a322e0a..c38fb80 100644
--- a/vpx_scale/generic/yv12extend.c
+++ b/vpx_scale/generic/yv12extend.c
@@ -9,6 +9,7 @@
  */
 
 #include <assert.h>
+#include "./vpx_config.h"
 #include "vpx_scale/yv12config.h"
 #include "vpx_mem/vpx_mem.h"
 #include "vpx_scale/vpx_scale.h"
@@ -94,6 +95,36 @@
                (ybf->border + ybf->y_width - ybf->y_crop_width + 1) / 2);
 }
 
+#if CONFIG_VP9
+void vp9_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf,
+                                int subsampling_x, int subsampling_y) {
+  const int c_w = (ybf->y_crop_width + subsampling_x) >> subsampling_x;
+  const int c_h = (ybf->y_crop_height + subsampling_y) >> subsampling_y;
+  const int c_et = ybf->border >> subsampling_y;
+  const int c_el = ybf->border >> subsampling_x;
+  const int c_eb = (ybf->border + ybf->y_height - ybf->y_crop_height +
+                    subsampling_y) >> subsampling_y;
+  const int c_er = (ybf->border + ybf->y_width - ybf->y_crop_width +
+                    subsampling_x) >> subsampling_x;
+
+  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);
+
+  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);
+
+  extend_plane(ybf->u_buffer, ybf->uv_stride,
+               c_w, c_h, c_et, c_el, c_eb, c_er);
+
+  extend_plane(ybf->v_buffer, ybf->uv_stride,
+               c_w, c_h, c_et, c_el, c_eb, c_er);
+}
+#endif
 
 /****************************************************************************
  *
diff --git a/vpx_scale/vpx_scale_rtcd.sh b/vpx_scale/vpx_scale_rtcd.sh
index e2bade0..b4f8907 100644
--- a/vpx_scale/vpx_scale_rtcd.sh
+++ b/vpx_scale/vpx_scale_rtcd.sh
@@ -24,3 +24,8 @@
 
 prototype void vp8_yv12_copy_y "struct yv12_buffer_config *src_ybc, struct yv12_buffer_config *dst_ybc"
 specialize vp8_yv12_copy_y neon
+
+if [ "$CONFIG_VP9" = "yes" ]; then
+    prototype void vp9_extend_frame_borders "struct yv12_buffer_config *ybf, int subsampling_x, int subsampling_y"
+    specialize vp9_extend_frame_borders
+fi
diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h
index 85396c0..7b8bd85 100644
--- a/vpx_scale/yv12config.h
+++ b/vpx_scale/yv12config.h
@@ -52,9 +52,14 @@
     int   uv_stride;
     /*    int   uvinternal_width; */
 
+    int   alpha_width;
+    int   alpha_height;
+    int   alpha_stride;
+
     uint8_t *y_buffer;
     uint8_t *u_buffer;
     uint8_t *v_buffer;
+    uint8_t *alpha_buffer;
 
     uint8_t *buffer_alloc;
     int buffer_alloc_sz;