gst/videobox/gstvideobox.c: Add AYUV->AYUV and AYUV->I420 formats.
authorDejan Sakelšak <sakdean@gmail.com>
Mon, 28 May 2007 15:01:33 +0000 (15:01 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 28 May 2007 15:01:33 +0000 (15:01 +0000)
Original commit message from CVS:
Based on patch by: Dejan Sakelšak <sakdean at gmail dot com>
* gst/videobox/gstvideobox.c: (gst_video_box_class_init),
(gst_video_box_set_property), (gst_video_box_transform_caps),
(video_box_recalc_transform), (gst_video_box_set_caps),
(gst_video_box_get_unit_size), (gst_video_box_apply_alpha),
(gst_video_box_ayuv_ayuv), (gst_video_box_clear), (UVfloor),
(UVceil), (gst_video_box_ayuv_i420), (gst_video_box_i420_ayuv),
(gst_video_box_i420_i420), (gst_video_box_transform),
(plugin_init):
Add AYUV->AYUV and AYUV->I420 formats.
Fix negotiation and I420->AYUV conversion.
Fixes #429329.

ChangeLog
gst/videobox/gstvideobox.c

index cd12c1f..345df31 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2007-05-28  Wim Taymans  <wim@fluendo.com>
+
+       Based on patch by: Dejan Sakelšak <sakdean at gmail dot com>
+
+       * gst/videobox/gstvideobox.c: (gst_video_box_class_init),
+       (gst_video_box_set_property), (gst_video_box_transform_caps),
+       (video_box_recalc_transform), (gst_video_box_set_caps),
+       (gst_video_box_get_unit_size), (gst_video_box_apply_alpha),
+       (gst_video_box_ayuv_ayuv), (gst_video_box_clear), (UVfloor),
+       (UVceil), (gst_video_box_ayuv_i420), (gst_video_box_i420_ayuv),
+       (gst_video_box_i420_i420), (gst_video_box_transform),
+       (plugin_init):
+       Add AYUV->AYUV and AYUV->I420 formats. 
+       Fix negotiation and I420->AYUV conversion.
+       Fixes #429329.
+
 2007-05-26  Wim Taymans  <wim@fluendo.com>
 
        * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data):
index 966569b..5fa3d59 100644 (file)
@@ -23,7 +23,7 @@
 #include <gst/gst.h>
 #include <gst/base/gstbasetransform.h>
 #include <gst/video/video.h>
-
+#include <math.h>
 #include <liboil/liboil.h>
 #include <string.h>
 
@@ -58,7 +58,9 @@ struct _GstVideoBox
   GstBaseTransform element;
 
   /* caps */
+  guint32 in_fourcc;
   gint in_width, in_height;
+  guint32 out_fourcc;
   gint out_width, out_height;
 
   gint box_left, box_right, box_top, box_bottom;
@@ -66,7 +68,6 @@ struct _GstVideoBox
   gint border_left, border_right, border_top, border_bottom;
   gint crop_left, crop_right, crop_top, crop_bottom;
 
-  gboolean use_alpha;
   gdouble alpha;
   gdouble border_alpha;
 
@@ -108,17 +109,19 @@ enum
 };
 
 static GstStaticPadTemplate gst_video_box_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
+    GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ AYUV, I420 }"))
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
+        GST_VIDEO_CAPS_YUV ("I420"))
     );
 
 static GstStaticPadTemplate gst_video_box_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
+        GST_VIDEO_CAPS_YUV ("I420"))
     );
 
 
@@ -130,6 +133,7 @@ static void gst_video_box_set_property (GObject * object, guint prop_id,
 static void gst_video_box_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
+static gboolean video_box_recalc_transform (GstVideoBox * video_box);
 static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
     GstPadDirection direction, GstCaps * from);
 static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
@@ -213,16 +217,14 @@ gst_video_box_class_init (GstVideoBoxClass * klass)
           "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
           G_PARAM_READWRITE));
 
+  trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
   trans_class->transform_caps =
       GST_DEBUG_FUNCPTR (gst_video_box_transform_caps);
   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_box_set_caps);
   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_video_box_get_unit_size);
-  trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
 
   GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
       "Resizes a video by adding borders or cropping");
-
-  oil_init ();
 }
 
 static void
@@ -247,6 +249,7 @@ gst_video_box_set_property (GObject * object, guint prop_id,
 {
   GstVideoBox *video_box = GST_VIDEO_BOX (object);
 
+  GST_BASE_TRANSFORM_LOCK (GST_BASE_TRANSFORM_CAST (video_box));
   switch (prop_id) {
     case PROP_LEFT:
       video_box->box_left = g_value_get_int (value);
@@ -301,6 +304,8 @@ gst_video_box_set_property (GObject * object, guint prop_id,
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+  video_box_recalc_transform (video_box);
+  GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box));
 }
 
 static void
@@ -342,48 +347,83 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
     GstPadDirection direction, GstCaps * from)
 {
   GstVideoBox *video_box;
-  GstCaps *to;
+  GstCaps *to, *ret;
+  const GstCaps *templ;
   GstStructure *structure;
-  GValue list_value = { 0 }, value = {
-  0};
-  gint dir, i, tmp;
+  GstPad *other;
+  gint width, height;
 
   video_box = GST_VIDEO_BOX (trans);
 
-  g_value_init (&list_value, GST_TYPE_LIST);
-  g_value_init (&value, GST_TYPE_FOURCC);
-  gst_value_set_fourcc (&value, GST_MAKE_FOURCC ('I', '4', '2', '0'));
-  gst_value_list_append_value (&list_value, &value);
-  g_value_unset (&value);
-
   to = gst_caps_copy (from);
-  dir = (direction == GST_PAD_SINK) ? -1 : 1;
-
-  for (i = 0; i < gst_caps_get_size (to); i++) {
-    structure = gst_caps_get_structure (to, i);
-    if (direction == GST_PAD_SINK) {    /* I420 to { I420, AYUV } */
-      g_value_init (&value, GST_TYPE_FOURCC);
-      gst_value_set_fourcc (&value, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'));
-      gst_value_list_append_value (&list_value, &value);
-      g_value_unset (&value);
-      gst_structure_set_value (structure, "format", &list_value);
-    } else if (direction == GST_PAD_SRC) {
-      gst_structure_set_value (structure, "format", &list_value);
+  structure = gst_caps_get_structure (to, 0);
+
+  /* get rid of format */
+  gst_structure_remove_field (structure, "format");
+
+  /* calculate width and height */
+  if (gst_structure_get_int (structure, "width", &width)) {
+    if (direction == GST_PAD_SINK) {
+      width -= video_box->box_left;
+      width -= video_box->box_right;
+    } else {
+      width += video_box->box_left;
+      width += video_box->box_right;
+    }
+    if (width <= 0)
+      width = 1;
+
+    GST_DEBUG ("New caps width: %d", width);
+    gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
+  }
+
+  if (gst_structure_get_int (structure, "height", &height)) {
+    if (direction == GST_PAD_SINK) {
+      height -= video_box->box_top;
+      height -= video_box->box_bottom;
+    } else {
+      height += video_box->box_top;
+      height += video_box->box_bottom;
     }
-    if (gst_structure_get_int (structure, "width", &tmp))
-      gst_structure_set (structure, "width", G_TYPE_INT,
-          tmp + dir * (video_box->box_left + video_box->box_right), NULL);
-    if (gst_structure_get_int (structure, "height", &tmp))
-      gst_structure_set (structure, "height", G_TYPE_INT,
-          tmp + dir * (video_box->box_top + video_box->box_bottom), NULL);
+
+    if (height <= 0)
+      height = 1;
+
+    GST_DEBUG ("New caps height: %d", height);
+    gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
   }
 
-  g_value_unset (&list_value);
+  /* filter against set allowed caps on the pad */
+  other = (direction == GST_PAD_SINK) ? trans->srcpad : trans->sinkpad;
+
+  templ = gst_pad_get_pad_template_caps (other);
+  ret = gst_caps_intersect (to, templ);
+  gst_caps_unref (to);
 
   GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
-      " to %" GST_PTR_FORMAT, direction, from, to);
+      " to %" GST_PTR_FORMAT, direction, from, ret);
+
+  return ret;
+}
+
+static gboolean
+video_box_recalc_transform (GstVideoBox * video_box)
+{
+  gboolean res = TRUE;
 
-  return to;
+  /* if we have the same format in and out and we don't need to perform and
+   * cropping at all, we can just operate in passthorugh mode */
+  if (video_box->in_fourcc == video_box->out_fourcc &&
+      video_box->box_left == 0 && video_box->box_right == 0 &&
+      video_box->box_top == 0 && video_box->box_bottom == 0) {
+
+    GST_LOG_OBJECT (video_box, "we are using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
+  } else {
+    GST_LOG_OBJECT (video_box, "we are not using passthrough");
+    gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), FALSE);
+  }
+  return res;
 }
 
 static gboolean
@@ -392,34 +432,37 @@ gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
   GstVideoBox *video_box;
   GstStructure *structure;
   gboolean ret;
-  guint32 fourcc = 0;
 
   video_box = GST_VIDEO_BOX (trans);
 
   structure = gst_caps_get_structure (in, 0);
   ret = gst_structure_get_int (structure, "width", &video_box->in_width);
   ret &= gst_structure_get_int (structure, "height", &video_box->in_height);
+  ret &= gst_structure_get_fourcc (structure, "format", &video_box->in_fourcc);
 
   structure = gst_caps_get_structure (out, 0);
   ret &= gst_structure_get_int (structure, "width", &video_box->out_width);
   ret &= gst_structure_get_int (structure, "height", &video_box->out_height);
-  ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
+  ret &= gst_structure_get_fourcc (structure, "format", &video_box->out_fourcc);
 
-  if (fourcc == GST_STR_FOURCC ("AYUV")) {
-    video_box->use_alpha = TRUE;
-  } else {
-    if (video_box->box_left == 0 && video_box->box_right == 0 &&
-        video_box->box_top == 0 && video_box->box_bottom == 0) {
-      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
-      GST_LOG ("we are using passthrough");
-    } else {
-      gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box),
-          FALSE);
-      GST_LOG ("we are not using passthrough");
-    }
-  }
+  /* something wrong getting the caps */
+  if (!ret)
+    goto no_caps;
+
+  GST_DEBUG ("Input w: %d h: %d", video_box->in_width, video_box->in_height);
+  GST_DEBUG ("Output w: %d h: %d", video_box->out_width, video_box->out_height);
+
+  /* recalc the transformation strategy */
+  ret = video_box_recalc_transform (video_box);
 
   return ret;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (video_box, "Could not get all caps fields");
+    return FALSE;
+  }
 }
 
 /* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */
@@ -437,6 +480,7 @@ static gboolean
 gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
     guint * size)
 {
+
   GstVideoBox *video_box;
   GstStructure *structure = NULL;
   guint32 fourcc;
@@ -463,6 +507,8 @@ gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
       break;
   }
 
+  GST_LOG_OBJECT (video_box, "Returning from _unit_size %d", *size);
+
   return TRUE;
 }
 
@@ -501,74 +547,397 @@ gst_video_box_copy_plane_i420 (GstVideoBox * video_box, guint8 * src,
 }
 
 static void
-gst_video_box_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest)
+gst_video_box_apply_alpha (guint8 * dest, guint8 alpha)
 {
-  guint8 *srcY, *srcU, *srcV;
-  guint8 *destY, *destU, *destV;
-  gint crop_width, crop_height;
-  gint out_width, out_height;
-  gint src_width, src_height;
-  gint src_stride, dest_stride;
-  gint br, bl, bt, bb;
+  if (dest[0] != 0)
+    dest[0] = alpha;
+}
 
-  br = video_box->border_right;
-  bl = video_box->border_left;
-  bt = video_box->border_top;
-  bb = video_box->border_bottom;
+static void
+gst_video_box_ayuv_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
+{
+  gint dblen = video_box->out_height * video_box->out_width;
+  guint32 *destb = (guint32 *) dest;
+  guint32 *srcb = (guint32 *) src;
+  guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
+  guint8 i_alpha = (guint8) (video_box->alpha * 255);
+  gint br, bl, bt, bb, crop_w, crop_h;
+  gint i;
+  guint32 *loc = destb;
+  guint32 empty_pixel;
+
+  GST_LOG ("Processing AYUV -> AYUV data");
+
+  crop_h = 0;
+  crop_w = 0;
+  empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
+      (yuv_colors_Y[video_box->fill_type] << 16) |
+      (yuv_colors_U[video_box->fill_type] << 8) |
+      yuv_colors_V[video_box->fill_type]);
+
+  br = video_box->box_right;
+  bl = video_box->box_left;
+  bt = video_box->box_top;
+  bb = video_box->box_bottom;
+
+  if (br >= 0 && bl >= 0) {
+    crop_w = video_box->in_width - (br + bl);
+  } else if (br >= 0 && bl < 0) {
+    crop_w = video_box->in_width - (br);
+  } else if (br < 0 && bl >= 0) {
+    crop_w = video_box->in_width - (bl);
+  } else if (br < 0 && bl < 0) {
+    crop_w = video_box->in_width;
+  }
 
-  out_width = video_box->out_width;
-  out_height = video_box->out_height;
+  if (bb >= 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bb + bt);
+  } else if (bb >= 0 && bt < 0) {
+    crop_h = video_box->in_height - (bb);
+  } else if (bb < 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bt);
+  } else if (bb < 0 && bt < 0) {
+    crop_h = video_box->in_height;
+  }
 
-  src_width = video_box->in_width;
-  src_height = video_box->in_height;
+  GST_DEBUG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb);
+  GST_DEBUG ("Alpha value is: %d", i_alpha);
 
-  crop_width = src_width - (video_box->crop_left + video_box->crop_right);
-  crop_height = src_height - (video_box->crop_top + video_box->crop_bottom);
+  if (crop_h <= 0 || crop_w <= 0) {
 
-  /* Y plane */
-  src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (src_width);
-  dest_stride = GST_VIDEO_I420_Y_ROWSTRIDE (out_width);
+    oil_splat_u32_ns (destb, &empty_pixel, dblen);
 
-  destY = dest + GST_VIDEO_I420_Y_OFFSET (out_width, out_height);
+  } else {
 
-  srcY = src + GST_VIDEO_I420_Y_OFFSET (src_width, src_height);
-  srcY += src_stride * video_box->crop_top + video_box->crop_left;
+    guint32 *src_loc = srcb;
 
-  gst_video_box_copy_plane_i420 (video_box, srcY, destY, br, bl, bt, bb,
-      crop_width, crop_height, src_stride, out_width, dest_stride,
-      yuv_colors_Y[video_box->fill_type]);
+    /* Top border */
+    if (bt < 0) {
+      oil_splat_u32_ns (loc, &empty_pixel, (-bt) * video_box->out_width);
+      loc = loc + ((-bt) * video_box->out_width);
+    } else {
+      src_loc = src_loc + (bt * video_box->in_width);
+    }
 
-  /* U plane */
-  src_stride = GST_VIDEO_I420_U_ROWSTRIDE (src_width);
-  dest_stride = GST_VIDEO_I420_U_ROWSTRIDE (out_width);
+    if (bl >= 0)
+      src_loc += bl;
 
-  destU = dest + GST_VIDEO_I420_U_OFFSET (out_width, out_height);
+    for (i = 0; i < crop_h; i++) {
+      gint j;
 
-  srcU = src + GST_VIDEO_I420_U_OFFSET (src_width, src_height);
-  srcU += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+      /* Left border */
+      if (bl < 0) {
+        oil_splat_u32_ns (loc, &empty_pixel, -bl);
+        loc += (-bl);
+      }
 
-  gst_video_box_copy_plane_i420 (video_box, srcU, destU, br / 2, bl / 2, bt / 2,
-      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
-      dest_stride, yuv_colors_U[video_box->fill_type]);
+      /* Cropped area */
+      oil_copy_u8 ((guint8 *) loc, (guint8 *) src_loc, crop_w * 4);
 
-  /* V plane */
-  src_stride = GST_VIDEO_I420_V_ROWSTRIDE (src_width);
-  dest_stride = GST_VIDEO_I420_V_ROWSTRIDE (out_width);
+      for (j = 0; j < crop_w; j++)
+        gst_video_box_apply_alpha ((guint8 *) & loc[j], i_alpha);
 
-  destV = dest + GST_VIDEO_I420_V_OFFSET (out_width, out_height);
+      src_loc += video_box->in_width;
+      loc += crop_w;
 
-  srcV = src + GST_VIDEO_I420_V_OFFSET (src_width, src_height);
-  srcV += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+      /* Right border */
+      if (br < 0) {
+        oil_splat_u32_ns (loc, &empty_pixel, -br);
+        loc += (-br);
+      }
+    }
 
-  gst_video_box_copy_plane_i420 (video_box, srcV, destV, br / 2, bl / 2, bt / 2,
-      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
-      dest_stride, yuv_colors_V[video_box->fill_type]);
+    /* Bottom border */
+    if (bb < 0) {
+      oil_splat_u32_ns (loc, &empty_pixel, (-bb) * video_box->out_width);
+    }
+  }
+
+  GST_LOG ("image created");
+
+}
+
+static gpointer
+gst_video_box_clear (gpointer dest, gint size)
+{
+  guint8 nil = 255;
+
+  oil_splat_u8_ns (dest, &nil, size);
+
+  return dest;
+}
+
+static gint
+UVfloor (gint j)
+{
+  return floor (((float) j) / 2);
+}
+
+static gint
+UVceil (gint j)
+{
+  return ceil (((float) j) / 2);
+}
+
+static void
+gst_video_box_ayuv_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest)
+{
+  gint br, bl, bt, bb, crop_w, crop_h, rest;
+  gint Ysize, Usize, Vsize;
+  guint8 *Ydest, *Udest, *Vdest;
+  guint8 *Utemp, *Vtemp;
+  guint32 empty_px_values[3];
+  gint i, j;
+  guint Ywidth, Uwidth, Vwidth;
+
+  GST_DEBUG ("AYUV to I420 conversion");
+
+  crop_h = 0;
+  crop_w = 0;
+  rest = 0;
+
+  empty_px_values[0] = yuv_colors_Y[video_box->fill_type];
+  empty_px_values[1] = yuv_colors_U[video_box->fill_type];
+  empty_px_values[2] = yuv_colors_V[video_box->fill_type];
+
+  Ywidth = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->out_width);
+  Uwidth = GST_VIDEO_I420_U_ROWSTRIDE (video_box->out_width);
+  Vwidth = GST_VIDEO_I420_V_ROWSTRIDE (video_box->out_width);
+
+  Ydest = dest + GST_VIDEO_I420_Y_OFFSET (video_box->out_width,
+      video_box->out_height);
+  Udest = Ydest + GST_VIDEO_I420_U_OFFSET (video_box->out_width,
+      video_box->out_height);
+  Vdest = Ydest + GST_VIDEO_I420_V_OFFSET (video_box->out_width,
+      video_box->out_height);
+
+  Ysize = Ywidth * video_box->out_height;
+  Usize = Uwidth * UVceil (video_box->out_height);
+  Vsize = Vwidth * UVceil (video_box->out_height);
+
+  br = video_box->box_right;
+  bl = video_box->box_left;
+  bt = video_box->box_top;
+  bb = video_box->box_bottom;
+
+  if (br >= 0 && bl >= 0) {
+    rest = Ywidth - video_box->out_width;
+    crop_w = video_box->in_width - (bl + br);
+  } else if (br >= 0 && bl < 0) {
+    rest = Ywidth - video_box->out_width;
+    crop_w = video_box->in_width - (br);
+  } else if (br < 0 && bl >= 0) {
+    rest = Ywidth - video_box->out_width;
+    crop_w = video_box->in_width - (bl);
+  } else if (br < 0 && bl < 0) {
+    rest = Ywidth - video_box->out_width;
+    crop_w = video_box->in_width;
+  }
+
+  if (bb >= 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bb + bt);
+  } else if (bb >= 0 && bt < 0) {
+    crop_h = video_box->in_height - (bb);
+  } else if (bb < 0 && bt >= 0) {
+    crop_h = video_box->in_height - (bt);
+  } else if (bb < 0 && bt < 0) {
+    crop_h = video_box->in_height;
+  }
+
+  Utemp = g_try_malloc0 (Uwidth);
+  Vtemp = g_try_malloc0 (Vwidth);
+
+  GST_DEBUG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb);
+
+  GST_DEBUG ("Starting conversion");
+
+  if (crop_h <= 0 || crop_w <= 0) {
+
+    oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], Ysize);
+    oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1], Usize);
+    oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2], Vsize);
+
+  } else {
+
+    gboolean sumbuff = FALSE;
+    guint32 *src_loc1;
+    gint a = 0;
+
+    src_loc1 = (guint32 *) src;
+
+    if (bt < 0) {
+      oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bt) * Ywidth);
+
+      oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
+          (UVfloor (-bt) * Uwidth) + 7);
+      oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
+          UVfloor (-bt) * Vwidth);
+
+      if ((-bt) % 2 > 0) {
+        oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[1], Uwidth);
+        oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[2], Vwidth);
+        sumbuff = TRUE;
+      }
+
+      Ydest += ((-bt) * Ywidth);
+      Udest += (UVfloor (-bt) * Uwidth);
+      Vdest += (UVfloor (-bt) * Vwidth);
+
+    } else {
+      src_loc1 = src_loc1 + (bt * video_box->in_width);
+    }
+
+    if (bl >= 0)
+      src_loc1 += bl;
+
+    GST_DEBUG ("Cropped area");
+    GST_DEBUG ("Ydest value: %d Ywidth: %d", Ydest, Ywidth);
+    GST_DEBUG ("Udest value: %d Uwidth: %d", Udest, Uwidth);
+    GST_DEBUG ("Vdest value: %d Vwidth: %d", Vdest, Vwidth);
+    GST_DEBUG ("Rest: %d", rest);
+    for (i = 0; i < crop_h; i++) {
+
+      a = 0;
+      if (sumbuff) {
+        // left border
+        if (bl < 0) {
+          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);
+
+          for (j = 0; j < -bl; j++) {
+            Utemp[UVfloor (j)] = (Utemp[UVfloor (j)] + empty_px_values[1]) / 2;
+            Vtemp[UVfloor (j)] = (Vtemp[UVfloor (j)] + empty_px_values[2]) / 2;
+          }
+          Ydest += -bl;
+          a = -bl;
+        }
+
+        for (j = 0; j < crop_w; j++) {
+          // check ARCH 
+          Ydest[j] = ((guint8 *) & src_loc1[j])[1];
+          Utemp[UVfloor (a + j)] =
+              (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
+          Vtemp[UVfloor (a + j)] =
+              (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
+        }
+        Ydest += crop_w;
+
+        // right border
+        if (br < 0) {
+          a = 0;
+          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
+          for (j = 0; j < -br; j++) {
+            Utemp[UVfloor (a + crop_w + j)] =
+                (Utemp[UVfloor (a + crop_w + j)] + empty_px_values[1]) / 2;
+            Vtemp[UVfloor (a + crop_w + j)] =
+                (Vtemp[UVfloor (a + crop_w + j)] + empty_px_values[2]) / 2;
+          }
+          Ydest += -br;
+        }
+        oil_copy_u8 (Udest, Utemp, Uwidth);
+        oil_copy_u8 (Vdest, Vtemp, Vwidth);
+        Udest += Uwidth;
+        Vdest += Vwidth;
+        Ydest += rest;
+        gst_video_box_clear (Utemp, Uwidth);
+        gst_video_box_clear (Vtemp, Vwidth);
+        src_loc1 += video_box->in_width;
+        sumbuff = FALSE;
+
+      } else {
+
+        // left border
+        a = 0;
+        if (bl < 0) {
+          //GST_DEBUG("Left border");
+          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -bl);
+          oil_splat_u8_ns (Vtemp, (guint8 *) & empty_px_values[1],
+              UVceil (-bl));
+          oil_splat_u8_ns (Utemp, (guint8 *) & empty_px_values[2],
+              UVceil (-bl));
+          Ydest += -bl;
+          a = -bl;
+        }
+
+        for (j = 0; j < crop_w; j++) {
+
+          // check ARCH 
+          Ydest[j] = ((guint8 *) & src_loc1[j])[1];
+
+          if ((a + j) % 2 > 0) {
+            Utemp[UVfloor (a + j)] =
+                (Utemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[2]) / 2;
+            Vtemp[UVfloor (a + j)] =
+                (Vtemp[UVfloor (a + j)] + ((guint8 *) & src_loc1[j])[3]) / 2;
+          } else {
+            Utemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[2] / 2;
+            Vtemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[3] / 2;
+          }
+        }
+        Ydest += crop_w;
+
+        // right border
+        if (br < 0) {
+          j = 0;
+          if ((a + crop_w) % 2 > 0) {
+            Utemp[UVfloor (a + crop_w)] =
+                (Utemp[UVfloor (a + crop_w)] + empty_px_values[1]) / 2;
+            Vtemp[UVfloor (a + crop_w)] =
+                (Vtemp[UVfloor (a + crop_w)] + empty_px_values[2]) / 2;
+            a++;
+            j = -1;
+          }
+
+          oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], -br);
+          oil_splat_u8_ns (&Utemp[UVfloor (a + crop_w)],
+              (guint8 *) & empty_px_values[1], UVceil ((-br) + j));
+          oil_splat_u8_ns (&Vtemp[UVfloor (a + crop_w)],
+              (guint8 *) & empty_px_values[2], UVceil ((-br) + j));
+          Ydest += -br;
+        }
+        Ydest += rest;
+        src_loc1 += video_box->in_width;
+        sumbuff = TRUE;
+
+      }
+    }
+
+    // bottom border 
+    if (bb < 0) {
+      a = 0;
+      oil_splat_u8_ns (Ydest, (guint8 *) & empty_px_values[0], (-bb) * Ywidth);
+      if (sumbuff) {
+        for (i = 0; i < Uwidth; i++) {
+          Utemp[i] = (Utemp[i] + empty_px_values[1]) / 2;
+        }
+        for (i = 0; i < Vwidth; i++) {
+          Vtemp[i] = (Vtemp[i] + empty_px_values[2]) / 2;
+        }
+
+        oil_copy_u8 (Udest, Utemp, Uwidth);
+        oil_copy_u8 (Vdest, Vtemp, Vwidth);
+        Udest += Uwidth;
+        Vdest += Vwidth;
+        sumbuff = FALSE;
+        a = -1;
+      }
+      oil_splat_u8_ns (Udest, (guint8 *) & empty_px_values[1],
+          (UVfloor ((-bb))) * Uwidth);
+      oil_splat_u8_ns (Vdest, (guint8 *) & empty_px_values[2],
+          (UVfloor ((-bb))) * Vwidth);
+    }
+    if (sumbuff) {
+      oil_copy_u8 (Udest, Utemp, Uwidth);
+      oil_copy_u8 (Vdest, Vtemp, Vwidth);
+    }
+  }
+
+  GST_LOG ("image created");
+  g_free (Utemp);
+  g_free (Vtemp);
 }
 
-/* Note the source image is always I420, we
- * are converting to AYUV on the fly here */
 static void
-gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
+gst_video_box_i420_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
 {
   guint8 *srcY, *srcU, *srcV;
   gint crop_width, crop_width2, crop_height;
@@ -579,7 +948,8 @@ gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
   gint i, j;
   guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
   guint8 i_alpha = (guint8) (video_box->alpha * 255);
-  guint32 *destp = (guint32 *) dest;
+  guint32 *destp;
+  guint32 *destb = (guint32 *) dest;
   guint32 ayuv;
 
   br = video_box->border_right;
@@ -594,11 +964,11 @@ gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
   src_strideu = GST_VIDEO_I420_U_ROWSTRIDE (video_box->in_width);
   src_stridev = GST_VIDEO_I420_V_ROWSTRIDE (video_box->in_width);
 
-  crop_width =
-      video_box->in_width - (video_box->crop_left + video_box->crop_right);
+  crop_width = video_box->in_width;
+  crop_width -= (video_box->crop_left + video_box->crop_right);
   crop_width2 = crop_width / 2;
-  crop_height =
-      video_box->in_height - (video_box->crop_top + video_box->crop_bottom);
+  crop_height = video_box->in_height;
+  crop_height -= (video_box->crop_top + video_box->crop_bottom);
 
   srcY =
       src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height);
@@ -622,10 +992,11 @@ gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
   if (bt) {
     size_t nb_pixels = bt * out_width;
 
-    oil_splat_u32_ns (destp, &ayuv, nb_pixels);
-    destp += nb_pixels;
+    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
+    destb += nb_pixels;
   }
   for (i = 0; i < crop_height; i++) {
+    destp = destb;
     /* left border */
     if (bl) {
       oil_splat_u32_ns (destp, &ayuv, bl);
@@ -652,7 +1023,7 @@ gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
       srcU += src_strideu - crop_width2;
       srcV += src_stridev - crop_width2;
     }
-    srcY += src_stridey - crop_width;
+    srcY += src_stridey - (crop_width2 * 2);
 
     destp = (guint32 *) dest;
     /* right border */
@@ -660,37 +1031,135 @@ gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
       oil_splat_u32_ns (destp, &ayuv, br);
       destp += br;
     }
+    destb += out_width;
   }
   /* bottom border */
   if (bb) {
     size_t nb_pixels = bb * out_width;
 
-    oil_splat_u32_ns (destp, &ayuv, nb_pixels);
-    destp += nb_pixels;
+    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
+    destb += nb_pixels;
   }
 }
 
+
+static void
+gst_video_box_i420_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest)
+{
+  guint8 *srcY, *srcU, *srcV;
+  guint8 *destY, *destU, *destV;
+  gint crop_width, crop_height;
+  gint out_width, out_height;
+  gint src_width, src_height;
+  gint src_stride, dest_stride;
+  gint br, bl, bt, bb;
+
+  br = video_box->border_right;
+  bl = video_box->border_left;
+  bt = video_box->border_top;
+  bb = video_box->border_bottom;
+
+  out_width = video_box->out_width;
+  out_height = video_box->out_height;
+
+  src_width = video_box->in_width;
+  src_height = video_box->in_height;
+
+  crop_width = src_width - (video_box->crop_left + video_box->crop_right);
+  crop_height = src_height - (video_box->crop_top + video_box->crop_bottom);
+
+  /* Y plane */
+  src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (src_width);
+  dest_stride = GST_VIDEO_I420_Y_ROWSTRIDE (out_width);
+
+  destY = dest + GST_VIDEO_I420_Y_OFFSET (out_width, out_height);
+
+  srcY = src + GST_VIDEO_I420_Y_OFFSET (src_width, src_height);
+  srcY += src_stride * video_box->crop_top + video_box->crop_left;
+
+  gst_video_box_copy_plane_i420 (video_box, srcY, destY, br, bl, bt, bb,
+      crop_width, crop_height, src_stride, out_width, dest_stride,
+      yuv_colors_Y[video_box->fill_type]);
+
+  /* U plane */
+  src_stride = GST_VIDEO_I420_U_ROWSTRIDE (src_width);
+  dest_stride = GST_VIDEO_I420_U_ROWSTRIDE (out_width);
+
+  destU = dest + GST_VIDEO_I420_U_OFFSET (out_width, out_height);
+
+  srcU = src + GST_VIDEO_I420_U_OFFSET (src_width, src_height);
+  srcU += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+
+  gst_video_box_copy_plane_i420 (video_box, srcU, destU, br / 2, bl / 2, bt / 2,
+      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
+      dest_stride, yuv_colors_U[video_box->fill_type]);
+
+  /* V plane */
+  src_stride = GST_VIDEO_I420_V_ROWSTRIDE (src_width);
+  dest_stride = GST_VIDEO_I420_V_ROWSTRIDE (out_width);
+
+  destV = dest + GST_VIDEO_I420_V_OFFSET (out_width, out_height);
+
+  srcV = src + GST_VIDEO_I420_V_OFFSET (src_width, src_height);
+  srcV += src_stride * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+
+  gst_video_box_copy_plane_i420 (video_box, srcV, destV, br / 2, bl / 2, bt / 2,
+      bb / 2, crop_width / 2, crop_height / 2, src_stride, out_width / 2,
+      dest_stride, yuv_colors_V[video_box->fill_type]);
+}
+
 static GstFlowReturn
 gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
     GstBuffer * out)
 {
   GstVideoBox *video_box;
+  guint8 *indata, *outdata;
 
   video_box = GST_VIDEO_BOX (trans);
 
-  if (video_box->use_alpha) {
-    gst_video_box_ayuv (video_box, GST_BUFFER_DATA (in), GST_BUFFER_DATA (out));
-  } else {
-    gst_video_box_i420 (video_box, GST_BUFFER_DATA (in), GST_BUFFER_DATA (out));
-  }
+  indata = GST_BUFFER_DATA (in);
+  outdata = GST_BUFFER_DATA (out);
 
+  switch (video_box->in_fourcc) {
+    case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+      switch (video_box->out_fourcc) {
+        case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+          gst_video_box_ayuv_ayuv (video_box, indata, outdata);
+          break;
+        case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+          gst_video_box_ayuv_i420 (video_box, indata, outdata);
+          break;
+        default:
+          goto invalid_format;
+      }
+      break;
+    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+      switch (video_box->out_fourcc) {
+        case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+          gst_video_box_i420_ayuv (video_box, indata, outdata);
+          break;
+        case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+          gst_video_box_i420_i420 (video_box, indata, outdata);
+          break;
+        default:
+          goto invalid_format;
+      }
+      break;
+    default:
+      goto invalid_format;
+  }
   return GST_FLOW_OK;
+
+  /* ERRORS */
+invalid_format:
+  {
+    return GST_FLOW_ERROR;
+  }
 }
 
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-
   return gst_element_register (plugin, "videobox", GST_RANK_NONE,
       GST_TYPE_VIDEO_BOX);
 }