videobox: Refactor boxing to reduce code duplication
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 22 Mar 2010 15:58:26 +0000 (16:58 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 26 Mar 2010 12:28:53 +0000 (13:28 +0100)
gst/videobox/gstvideobox.c
gst/videobox/gstvideobox.h

index 247c8a0..163c184 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (videobox_debug);
 #define GST_CAT_DEFAULT videobox_debug
 
+/* From videotestsrc.c */
+static const guint8 yuv_sdtv_colors_Y[VIDEO_BOX_FILL_LAST] = { 16, 145, 41 };
+static const guint8 yuv_sdtv_colors_U[VIDEO_BOX_FILL_LAST] = { 128, 54, 240 };
+static const guint8 yuv_sdtv_colors_V[VIDEO_BOX_FILL_LAST] = { 128, 34, 110 };
+
+static const guint8 yuv_hdtv_colors_Y[VIDEO_BOX_FILL_LAST] = { 16, 173, 32 };
+static const guint8 yuv_hdtv_colors_U[VIDEO_BOX_FILL_LAST] = { 128, 42, 240 };
+static const guint8 yuv_hdtv_colors_V[VIDEO_BOX_FILL_LAST] = { 128, 26, 118 };
+
+static const guint8 rgb_colors_R[VIDEO_BOX_FILL_LAST] = { 0, 255, 0 };
+static const guint8 rgb_colors_G[VIDEO_BOX_FILL_LAST] = { 0, 0, 0 };
+static const guint8 rgb_colors_B[VIDEO_BOX_FILL_LAST] = { 0, 255, 255 };
+
+/* Generated by -bad/ext/cog/generate_tables */
+static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
+  298, 0, 459, -63514,
+  298, -55, -136, 19681,
+  298, 541, 0, -73988,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  298, 0, 409, -57068,
+  298, -100, -208, 34707,
+  298, 516, 0, -70870,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
+  47, 157, 16, 4096,
+  -26, -87, 112, 32768,
+  112, -102, -10, 32768,
+};
+
+static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
+  66, 129, 25, 4096,
+  -38, -74, 112, 32768,
+  112, -94, -18, 32768,
+};
+
+static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
+  256, -30, -53, 10600,
+  0, 261, 29, -4367,
+  0, 19, 262, -3289,
+};
+
+static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
+  256, 25, 49, -9536,
+  0, 253, -28, 3958,
+  0, -19, 252, 2918,
+};
+
+#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
+
+static void
+fill_ayuv (GstVideoBoxFill fill_type, guint b_alpha, guint8 * dest,
+    gboolean sdtv, gint width, gint height, gint x, gint y, gint w, gint h)
+{
+  guint32 empty_pixel;
+
+  if (sdtv)
+    empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
+        (yuv_sdtv_colors_Y[fill_type] << 16) |
+        (yuv_sdtv_colors_U[fill_type] << 8) | yuv_sdtv_colors_V[fill_type]);
+  else
+    empty_pixel = GUINT32_FROM_BE ((b_alpha << 24) |
+        (yuv_hdtv_colors_Y[fill_type] << 16) |
+        (yuv_hdtv_colors_U[fill_type] << 8) | yuv_hdtv_colors_V[fill_type]);
+
+  if (width == w && height == h && x == 0 && y == 0) {
+    oil_splat_u32_ns ((guint32 *) dest, &empty_pixel, width * height);
+  } else {
+    gint i;
+    gint stride = 4 * width;
+
+    dest = dest + y * width * 4 + x * 4;
+    for (i = 0; i < h; i++) {
+      oil_splat_u32_ns ((guint32 *) dest, &empty_pixel, w);
+      dest += stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_ayuv (guint i_alpha, guint8 * dest, gboolean dest_sdtv,
+    gint dest_width, gint dest_height, gint dest_x, gint dest_y,
+    const guint8 * src, gboolean src_sdtv, gint src_width, gint src_height,
+    gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  gint src_stride = 4 * src_width;
+  gint dest_stride = 4 * dest_width;
+
+  dest = dest + dest_y * dest_width * 4 + dest_x * 4;
+  src = src + src_y * src_width * 4 + src_x * 4;
+
+  w *= 4;
+
+  if (dest_sdtv != src_sdtv) {
+    gint matrix[12];
+    gint y, u, v;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        dest[j] = (src[j] * i_alpha) >> 8;
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+        dest[j + 1] = APPLY_MATRIX (matrix, 0, y, u, v);
+        dest[j + 2] = APPLY_MATRIX (matrix, 1, y, u, v);
+        dest[j + 3] = APPLY_MATRIX (matrix, 2, y, u, v);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        dest[j] = (src[j] * i_alpha) >> 8;
+        dest[j + 1] = src[j + 1];
+        dest[j + 2] = src[j + 2];
+        dest[j + 3] = src[j + 3];
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_i420 (guint i_alpha, guint8 * dest, gboolean dest_sdtv,
+    gint dest_width, gint dest_height, gint dest_x, gint dest_y,
+    const guint8 * src, gboolean src_sdtv, gint src_width, gint src_height,
+    gint src_x, gint src_y, gint w, gint h)
+{
+  gint i, j;
+  guint8 *destY, *destU, *destV;
+  gint dest_strideY, dest_strideUV;
+  gint widthY, widthUV;
+  gint hY, hUV;
+
+  dest_strideY =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, dest_width);
+  dest_strideUV =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, dest_width);
+
+  destY =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
+      dest_width, dest_height);
+  destU =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
+      dest_width, dest_height);
+  destV =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
+      dest_width, dest_height);
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + (dest_y / 2) * dest_strideUV + dest_x / 2;
+  destV = destV + (dest_y / 2) * dest_strideUV + dest_x / 2;
+
+  src = src + src_y * src_width * 4 + src_x * 4;
+
+  widthY = w;
+  widthUV = (w + 1) / 2;
+
+  hY = h;
+  hUV = (h + 1) / 2;
+
+  if (src_sdtv != dest_sdtv) {
+    gint matrix[12];
+    gint y1, y2, y3, y4;
+    gint u1, u2, u3, u4;
+    gint v1, v2, v3, v4;
+    guint8 *destY2 = destY + dest_strideY;
+    const guint8 *src2 = src + src_width * 4;
+
+    dest_strideY *= 2;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < hUV; i++) {
+      if (i * 2 == hY) {
+        destY2 = destY;
+      }
+
+      for (j = 0; j < widthUV; j++) {
+        y1 = src[8 * j + 1];
+        u1 = src[8 * j + 2];
+        v1 = src[8 * j + 3];
+        y2 = src[8 * j + 5];
+        u2 = src[8 * j + 6];
+        v2 = src[8 * j + 7];
+
+        if (j * 2 < widthY) {
+          y3 = src2[8 * j + 1];
+          u3 = src2[8 * j + 2];
+          v3 = src2[8 * j + 3];
+          y4 = src2[8 * j + 5];
+          u4 = src2[8 * j + 6];
+          v4 = src2[8 * j + 7];
+        } else {
+          y3 = y1;
+          u3 = u1;
+          v3 = v1;
+          y4 = y2;
+          u4 = u2;
+          v4 = v2;
+        }
+
+        y1 = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+        u1 = APPLY_MATRIX (matrix, 1, y1, u1, v1);
+        v1 = APPLY_MATRIX (matrix, 2, y1, u1, v1);
+
+        y3 = APPLY_MATRIX (matrix, 0, y3, u3, v3);
+        u3 = APPLY_MATRIX (matrix, 1, y3, u3, v3);
+        v3 = APPLY_MATRIX (matrix, 2, y3, u3, v3);
+
+        if (j * 2 < widthY) {
+          y2 = APPLY_MATRIX (matrix, 0, y2, u2, v2);
+          u2 = APPLY_MATRIX (matrix, 1, y2, u2, v2);
+          v2 = APPLY_MATRIX (matrix, 2, y2, u2, v2);
+
+          y4 = APPLY_MATRIX (matrix, 0, y4, u4, v4);
+          u4 = APPLY_MATRIX (matrix, 1, y4, u4, v4);
+          v4 = APPLY_MATRIX (matrix, 2, y4, u4, v4);
+        } else {
+          u2 = u1;
+          v2 = v1;
+          u4 = u3;
+          v4 = v3;
+        }
+
+        destY[2 * j] = y1;
+        destY2[2 * j] = y3;
+        if (j * 2 < widthY) {
+          destY[2 * j + 1] = y2;
+          destY2[2 * j + 1] = y4;
+        }
+
+        destU[j] = (u1 + u2 + u3 + u4) / 4;
+        destV[j] = (v1 + v2 + v3 + v4) / 4;
+      }
+      src += src_width * 8;
+      destY += dest_strideY;
+      src2 += src_width * 8;
+      destY2 += dest_strideY;
+
+      destU += dest_strideUV;
+      destV += dest_strideUV;
+    }
+  } else {
+    gint y1, y2, y3, y4;
+    gint u1, u2, u3, u4;
+    gint v1, v2, v3, v4;
+    guint8 *destY2 = destY + dest_strideY;
+    const guint8 *src2 = src + src_width * 4;
+
+    dest_strideY *= 2;
+
+    for (i = 0; i < hUV; i++) {
+      if (i * 2 == hY) {
+        destY2 = destY;
+      }
+
+      for (j = 0; j < widthUV; j++) {
+        y1 = src[8 * j + 1];
+        u1 = src[8 * j + 2];
+        v1 = src[8 * j + 3];
+        y2 = src[8 * j + 5];
+        u2 = src[8 * j + 6];
+        v2 = src[8 * j + 7];
+
+        if (j * 2 < widthY) {
+          y3 = src2[8 * j + 1];
+          u3 = src2[8 * j + 2];
+          v3 = src2[8 * j + 3];
+          y4 = src2[8 * j + 5];
+          u4 = src2[8 * j + 6];
+          v4 = src2[8 * j + 7];
+        } else {
+          y3 = y1;
+          u3 = u1;
+          v3 = v1;
+          y4 = y2;
+          u4 = u2;
+          v4 = v2;
+        }
+
+        destY[2 * j] = y1;
+        destY2[2 * j] = y3;
+        if (j * 2 < widthY) {
+          destY[2 * j + 1] = y2;
+          destY2[2 * j + 1] = y4;
+        }
+
+        destU[j] = (u1 + u2 + u3 + u4) / 4;
+        destV[j] = (v1 + v2 + v3 + v4) / 4;
+      }
+      src += src_width * 8;
+      destY += dest_strideY;
+      src2 += src_width * 8;
+      destY2 += dest_strideY;
+
+      destU += dest_strideUV;
+      destV += dest_strideUV;
+    }
+  }
+}
+
+static void
+fill_i420 (GstVideoBoxFill fill_type, guint b_alpha, guint8 * dest,
+    gboolean sdtv, gint width, gint height, gint x, gint y, gint w, gint h)
+{
+  guint8 empty_pixel[3];
+  guint8 *destY, *destU, *destV;
+  gint strideY, strideUV;
+  gint heightY, heightUV;
+
+  if (sdtv) {
+    empty_pixel[0] = yuv_sdtv_colors_Y[fill_type];
+    empty_pixel[1] = yuv_sdtv_colors_U[fill_type];
+    empty_pixel[2] = yuv_sdtv_colors_V[fill_type];
+  } else {
+    empty_pixel[0] = yuv_hdtv_colors_Y[fill_type];
+    empty_pixel[1] = yuv_hdtv_colors_U[fill_type];
+    empty_pixel[2] = yuv_hdtv_colors_V[fill_type];
+  }
+
+  strideY = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width);
+  strideUV = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width);
+
+  destY =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
+      width, height);
+  destU =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
+      width, height);
+  destV =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
+      width, height);
+
+  heightY =
+      gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 0, height);
+  heightUV =
+      gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 1, height);
+
+  if (width == w && height == h && x == 0 && y == 0) {
+    oil_splat_u8_ns (destY, &empty_pixel[0], strideY * heightY);
+    oil_splat_u8_ns (destU, &empty_pixel[1], strideUV * heightUV);
+    oil_splat_u8_ns (destV, &empty_pixel[2], strideUV * heightUV);
+  } else {
+    gint i;
+    gint widthY, widthUV;
+    gint hY, hUV;
+
+    widthY = w;
+    widthUV = (w + 1) / 2;
+
+    hY = h;
+    hUV = (h + 1) / 2;
+
+    destY = destY + y * strideY + x;
+    destU = destU + (y / 2) * strideUV + x / 2;
+    destV = destV + (y / 2) * strideUV + x / 2;
+
+    for (i = 0; i < hY; i++) {
+      oil_splat_u8_ns (destY, &empty_pixel[0], widthY);
+      destY += strideY;
+    }
+
+    for (i = 0; i < hUV; i++) {
+      oil_splat_u8_ns (destU, &empty_pixel[1], widthUV);
+      oil_splat_u8_ns (destV, &empty_pixel[2], widthUV);
+      destU += strideUV;
+      destV += strideUV;
+    }
+  }
+}
+
+static void
+copy_i420_i420 (guint i_alpha, guint8 * dest, gboolean dest_sdtv,
+    gint dest_width, gint dest_height, gint dest_x, gint dest_y,
+    const guint8 * src, gboolean src_sdtv, gint src_width, gint src_height,
+    gint src_x, gint src_y, gint w, gint h)
+{
+  gint i;
+  guint8 *destY, *destU, *destV;
+  const guint8 *srcY, *srcU, *srcV;
+  gint dest_strideY, dest_strideUV;
+  gint src_strideY, src_strideUV;
+  gint widthY, widthUV;
+  gint hY, hUV;
+
+  dest_strideY =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, dest_width);
+  dest_strideUV =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, dest_width);
+  src_strideY =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
+  src_strideUV =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
+
+  destY =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
+      dest_width, dest_height);
+  destU =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
+      dest_width, dest_height);
+  destV =
+      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
+      dest_width, dest_height);
+
+  srcY =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
+      src_width, src_height);
+  srcU =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
+      src_width, src_height);
+  srcV =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
+      src_width, src_height);
+
+
+  destY = destY + dest_y * dest_strideY + dest_x;
+  destU = destU + (dest_y / 2) * dest_strideUV + dest_x / 2;
+  destV = destV + (dest_y / 2) * dest_strideUV + dest_x / 2;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + (src_y / 2) * src_strideUV + src_x / 2;
+  srcV = srcV + (src_y / 2) * src_strideUV + src_x / 2;
+
+  widthY = w;
+  widthUV = (w + 1) / 2;
+
+  hY = h;
+  hUV = (h + 1) / 2;
+
+  if (src_sdtv != dest_sdtv) {
+    gint matrix[12];
+    gint y1, y2, y3, y4;
+    gint u1, u2, u3, u4;
+    gint v1, v2, v3, v4;
+    gint j;
+    guint8 *destY2 = destY + dest_strideY;
+    const guint8 *srcY2 = srcY + src_strideY;
+
+    dest_strideY *= 2;
+    src_strideY *= 2;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < hUV; i++) {
+      if (i * 2 == hY) {
+        destY2 = destY;
+        srcY2 = srcY;
+      }
+
+      for (j = 0; j < widthUV; j++) {
+        y1 = srcY[2 * j];
+        y2 = srcY[2 * j + 1];
+        y3 = srcY2[2 * j];
+        y4 = srcY2[2 * j + 1];
+
+        u1 = u2 = u3 = u4 = srcU[j];
+        v1 = v2 = v3 = v4 = srcV[j];
+
+        y1 = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+        u1 = APPLY_MATRIX (matrix, 1, y1, u1, v1);
+        v1 = APPLY_MATRIX (matrix, 2, y1, u1, v1);
+
+        y2 = APPLY_MATRIX (matrix, 0, y2, u2, v2);
+        u2 = APPLY_MATRIX (matrix, 1, y2, u2, v2);
+        v2 = APPLY_MATRIX (matrix, 2, y2, u2, v2);
+
+        y3 = APPLY_MATRIX (matrix, 0, y3, u3, v3);
+        u3 = APPLY_MATRIX (matrix, 1, y3, u3, v3);
+        v3 = APPLY_MATRIX (matrix, 2, y3, u3, v3);
+
+        y4 = APPLY_MATRIX (matrix, 0, y4, u4, v4);
+        u4 = APPLY_MATRIX (matrix, 1, y4, u4, v4);
+        v4 = APPLY_MATRIX (matrix, 2, y4, u4, v4);
+
+        destY[2 * j] = y1;
+        destY[2 * j + 1] = y2;
+        destY2[2 * j] = y3;
+        destY2[2 * j + 1] = y4;
+
+        destU[j] = (u1 + u2 + u3 + u4) / 4;
+        destV[j] = (v1 + v2 + v3 + v4) / 4;
+      }
+      destY += dest_strideY;
+      srcY += src_strideY;
+      destY2 += dest_strideY;
+      srcY2 += src_strideY;
+
+      destU += dest_strideUV;
+      destV += dest_strideUV;
+      srcU += src_strideUV;
+      srcV += src_strideUV;
+    }
+  } else {
+    for (i = 0; i < hY; i++) {
+      oil_copy_u8 (destY, srcY, widthY);
+      destY += dest_strideY;
+      srcY += src_strideY;
+    }
+
+    for (i = 0; i < hUV; i++) {
+      oil_copy_u8 (destU, srcU, widthUV);
+      oil_copy_u8 (destV, srcV, widthUV);
+      destU += dest_strideUV;
+      destV += dest_strideUV;
+      srcU += src_strideUV;
+      srcV += src_strideUV;
+    }
+  }
+}
+
+static void
+copy_i420_ayuv (guint i_alpha, guint8 * dest, gboolean dest_sdtv,
+    gint dest_width, gint dest_height, gint dest_x, gint dest_y,
+    const guint8 * src, gboolean src_sdtv, gint src_width, gint src_height,
+    gint src_x, gint src_y, gint w, gint h)
+{
+  gint i;
+  const guint8 *srcY, *srcU, *srcV;
+  gint src_strideY, src_strideUV;
+  gint widthY, widthUV;
+  gint hY, hUV;
+
+  src_strideY =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
+  src_strideUV =
+      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
+
+  srcY =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
+      src_width, src_height);
+  srcU =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
+      src_width, src_height);
+  srcV =
+      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
+      src_width, src_height);
+
+
+  dest = dest + dest_y * dest_width * 4 + dest_x * 4;
+
+  srcY = srcY + src_y * src_strideY + src_x;
+  srcU = srcU + (src_y / 2) * src_strideUV + src_x / 2;
+  srcV = srcV + (src_y / 2) * src_strideUV + src_x / 2;
+
+  widthY = w;
+  widthUV = (w + 1) / 2;
+
+  hY = h;
+  hUV = (h + 1) / 2;
+
+  if (src_sdtv != dest_sdtv) {
+    gint matrix[12];
+    gint y1, y2, y3, y4;
+    gint u1, u2, u3, u4;
+    gint v1, v2, v3, v4;
+    gint j;
+    guint8 *dest2;
+    const guint8 *srcY2 = srcY + src_strideY;
+
+    dest2 = dest + dest_width * 4;
+
+    src_strideY *= 2;
+
+    memcpy (matrix,
+        dest_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
+        cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
+
+    for (i = 0; i < hUV; i++) {
+      if (i * 2 == hY) {
+        srcY2 = srcY;
+      }
+
+      for (j = 0; j < widthUV; j++) {
+        y1 = srcY[2 * j];
+        y3 = srcY2[2 * j];
+        y2 = (j * 2 < widthY) ? srcY[2 * j + 1] : y1;
+        y4 = (j * 2 < widthY) ? srcY2[2 * j + 1] : y3;
+
+        u1 = u2 = u3 = u4 = srcU[j];
+        v1 = v2 = v3 = v4 = srcV[j];
+
+        y1 = APPLY_MATRIX (matrix, 0, y1, u1, v1);
+        u1 = APPLY_MATRIX (matrix, 1, y1, u1, v1);
+        v1 = APPLY_MATRIX (matrix, 2, y1, u1, v1);
+
+        y3 = APPLY_MATRIX (matrix, 0, y3, u3, v3);
+        u3 = APPLY_MATRIX (matrix, 1, y3, u3, v3);
+        v3 = APPLY_MATRIX (matrix, 2, y3, u3, v3);
+
+        if (j * 2 < widthY) {
+          y2 = APPLY_MATRIX (matrix, 0, y2, u2, v2);
+          u2 = APPLY_MATRIX (matrix, 1, y2, u2, v2);
+          v2 = APPLY_MATRIX (matrix, 2, y2, u2, v2);
+
+          y4 = APPLY_MATRIX (matrix, 0, y4, u4, v4);
+          u4 = APPLY_MATRIX (matrix, 1, y4, u4, v4);
+          v4 = APPLY_MATRIX (matrix, 2, y4, u4, v4);
+        }
+
+        dest[8 * j] = i_alpha;
+        dest[8 * j + 1] = y1;
+        dest[8 * j + 2] = u1;
+        dest[8 * j + 3] = v1;
+        dest2[8 * j] = i_alpha;
+        dest2[8 * j + 1] = y3;
+        dest2[8 * j + 2] = u3;
+        dest2[8 * j + 3] = v3;
+        if (j * 2 < widthY) {
+          dest[8 * j + 4] = i_alpha;
+          dest[8 * j + 5] = y2;
+          dest[8 * j + 6] = u2;
+          dest[8 * j + 7] = v2;
+          dest2[8 * j + 4] = i_alpha;
+          dest2[8 * j + 5] = y4;
+          dest2[8 * j + 6] = u4;
+          dest2[8 * j + 7] = v4;
+        }
+      }
+      dest += dest_width * 8;
+      srcY += src_strideY;
+      dest2 += dest_width * 8;
+      srcY2 += src_strideY;
+
+      srcU += src_strideUV;
+      srcV += src_strideUV;
+    }
+  } else {
+    gint y1, y2, y3, y4;
+    gint u1, u2, u3, u4;
+    gint v1, v2, v3, v4;
+    gint j;
+    guint8 *dest2;
+    const guint8 *srcY2 = srcY + src_strideY;
+
+    dest2 = dest + dest_width * 4;
+
+    src_strideY *= 2;
+
+    for (i = 0; i < hUV; i++) {
+      if (i * 2 == hY) {
+        srcY2 = srcY;
+      }
+
+      for (j = 0; j < widthUV; j++) {
+        y1 = srcY[2 * j];
+        y3 = srcY2[2 * j];
+        y2 = (j * 2 < widthY) ? srcY[2 * j + 1] : y1;
+        y4 = (j * 2 < widthY) ? srcY2[2 * j + 1] : y3;
+
+        u1 = u2 = u3 = u4 = srcU[j];
+        v1 = v2 = v3 = v4 = srcV[j];
+
+        dest[8 * j] = i_alpha;
+        dest[8 * j + 1] = y1;
+        dest[8 * j + 2] = u1;
+        dest[8 * j + 3] = v1;
+        dest2[8 * j] = i_alpha;
+        dest2[8 * j + 1] = y3;
+        dest2[8 * j + 2] = u3;
+        dest2[8 * j + 3] = v3;
+        if (j * 2 < widthY) {
+          dest[8 * j + 4] = i_alpha;
+          dest[8 * j + 5] = y2;
+          dest[8 * j + 6] = u2;
+          dest[8 * j + 7] = v2;
+          dest2[8 * j + 4] = i_alpha;
+          dest2[8 * j + 5] = y4;
+          dest2[8 * j + 6] = u4;
+          dest2[8 * j + 7] = v4;
+        }
+      }
+      dest += dest_width * 8;
+      srcY += src_strideY;
+      dest2 += dest_width * 8;
+      srcY2 += src_strideY;
+
+      srcU += src_strideUV;
+      srcV += src_strideUV;
+    }
+  }
+}
+
 #define DEFAULT_LEFT      0
 #define DEFAULT_RIGHT     0
 #define DEFAULT_TOP       0
@@ -114,7 +810,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 gboolean gst_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,
@@ -123,6 +819,8 @@ static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
     GstCaps * caps, guint * size);
 static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
     GstBuffer * in, GstBuffer * out);
+static void gst_video_box_fixate_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
 
 #define GST_TYPE_VIDEO_BOX_FILL (gst_video_box_fill_get_type())
 static GType
@@ -232,6 +930,7 @@ gst_video_box_class_init (GstVideoBoxClass * klass)
       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->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_box_fixate_caps);
 }
 
 static void
@@ -317,7 +1016,7 @@ 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_video_box_recalc_transform (video_box);
 
   GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
   gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (video_box));
@@ -433,6 +1132,8 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
 
   /* get rid of format */
   gst_structure_remove_field (structure, "format");
+  gst_structure_remove_field (structure, "color-matrix");
+  gst_structure_remove_field (structure, "chroma-site");
 
   /* otherwise caps nego will fail: */
   if (video_box->autocrop) {
@@ -486,7 +1187,7 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
 }
 
 static gboolean
-video_box_recalc_transform (GstVideoBox * video_box)
+gst_video_box_recalc_transform (GstVideoBox * video_box)
 {
   gboolean res = TRUE;
 
@@ -494,7 +1195,8 @@ video_box_recalc_transform (GstVideoBox * video_box)
    * cropping at all, we can just operate in passthrough mode */
   if (video_box->in_format == video_box->out_format &&
       video_box->box_left == 0 && video_box->box_right == 0 &&
-      video_box->box_top == 0 && video_box->box_bottom == 0) {
+      video_box->box_top == 0 && video_box->box_bottom == 0 &&
+      video_box->in_sdtv == video_box->out_sdtv) {
 
     GST_LOG_OBJECT (video_box, "we are using passthrough");
     gst_base_transform_set_passthrough (GST_BASE_TRANSFORM_CAST (video_box),
@@ -508,10 +1210,48 @@ video_box_recalc_transform (GstVideoBox * video_box)
 }
 
 static gboolean
+gst_video_box_select_processing_functions (GstVideoBox * video_box)
+{
+  switch (video_box->out_format) {
+    case GST_VIDEO_FORMAT_AYUV:
+      video_box->fill = fill_ayuv;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_ayuv;
+          break;
+        case GST_VIDEO_FORMAT_I420:
+          video_box->copy = copy_i420_ayuv;
+          break;
+        default:
+          break;
+      }
+      break;
+    case GST_VIDEO_FORMAT_I420:
+      video_box->fill = fill_i420;
+      switch (video_box->in_format) {
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_i420;
+          break;
+        case GST_VIDEO_FORMAT_I420:
+          video_box->copy = copy_i420_i420;
+          break;
+        default:
+          break;
+      }
+      break;
+    default:
+      break;
+  }
+
+  return video_box->fill != NULL && video_box->copy != NULL;
+}
+
+static gboolean
 gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
 {
   GstVideoBox *video_box = GST_VIDEO_BOX (trans);
   gboolean ret;
+  const gchar *matrix;
 
   g_mutex_lock (video_box->mutex);
 
@@ -522,6 +1262,11 @@ gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
       gst_video_format_parse_caps (out, &video_box->out_format,
       &video_box->out_width, &video_box->out_height);
 
+  matrix = gst_video_parse_caps_color_matrix (in);
+  video_box->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
+  matrix = gst_video_parse_caps_color_matrix (out);
+  video_box->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
+
   /* something wrong getting the caps */
   if (!ret)
     goto no_caps;
@@ -535,8 +1280,10 @@ gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
     gst_video_box_autocrop (video_box);
 
   /* recalc the transformation strategy */
-  ret = video_box_recalc_transform (video_box);
+  ret = gst_video_box_recalc_transform (video_box);
 
+  if (ret)
+    ret = gst_video_box_select_processing_functions (video_box);
   g_mutex_unlock (video_box->mutex);
 
   return ret;
@@ -575,69 +1322,34 @@ gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
   return TRUE;
 }
 
-static const guint8 yuv_colors_Y[VIDEO_BOX_FILL_LAST] = { 16, 150, 29 };
-static const guint8 yuv_colors_U[VIDEO_BOX_FILL_LAST] = { 128, 46, 255 };
-static const guint8 yuv_colors_V[VIDEO_BOX_FILL_LAST] = { 128, 21, 107 };
-
 static void
-gst_video_box_copy_plane_i420 (GstVideoBox * video_box, const guint8 * src,
-    guint8 * dest, gint br, gint bl, gint bt, gint bb, gint src_crop_width,
-    gint src_crop_height, gint src_stride, gint dest_width, gint dest_stride,
-    guint8 fill_color)
+gst_video_box_fixate_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
 {
-  gint j;
-
-  /* top border */
-  for (j = 0; j < bt; j++) {
-    oil_splat_u8_ns (dest, &fill_color, dest_width);
-    dest += dest_stride;
-  }
-
-  /* copy and add left and right border */
-  for (j = 0; j < src_crop_height; j++) {
-    oil_splat_u8_ns (dest, &fill_color, bl);
-    oil_memcpy (dest + bl, src, src_crop_width);
-    oil_splat_u8_ns (dest + bl + src_crop_width, &fill_color, br);
-    dest += dest_stride;
-    src += src_stride;
-  }
+  gint width, height;
+  GstStructure *s;
+  gboolean ret;
 
-  /* bottom border */
-  for (j = 0; j < bb; j++) {
-    oil_splat_u8_ns (dest, &fill_color, dest_width);
-    dest += dest_stride;
-  }
-}
+  ret = gst_video_format_parse_caps (caps, NULL, &width, &height);
+  if (!ret)
+    return;
 
-static void
-gst_video_box_apply_alpha (guint8 * dest, guint8 alpha)
-{
-  if (dest[0] != 0)
-    dest[0] = alpha;
+  s = gst_caps_get_structure (othercaps, 0);
+  gst_structure_fixate_field_nearest_int (s, "width", width);
+  gst_structure_fixate_field_nearest_int (s, "height", height);
 }
 
 static void
-gst_video_box_ayuv_ayuv (GstVideoBox * video_box, const guint8 * src,
+gst_video_box_process (GstVideoBox * video_box, const guint8 * src,
     guint8 * dest)
 {
-  gint dblen = video_box->out_height * video_box->out_width;
-  guint32 *destb = (guint32 *) dest;
-  const guint32 *srcb = (const guint32 *) src;
-  guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
-  guint8 i_alpha = (guint8) (video_box->alpha * 255);
+  guint b_alpha = CLAMP ((guint) video_box->border_alpha * 256, 0, 256);
+  guint i_alpha = CLAMP ((guint) video_box->alpha * 256, 0, 256);
+  GstVideoBoxFill fill_type = video_box->fill_type;
   gint br, bl, bt, bb, crop_w, crop_h;
-  gint i;
-  guint32 *loc = destb;
-  guint32 empty_pixel;
-
-  GST_LOG_OBJECT (video_box, "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;
@@ -666,547 +1378,62 @@ gst_video_box_ayuv_ayuv (GstVideoBox * video_box, const guint8 * src,
 
   GST_DEBUG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br,
       bt, bb);
-  GST_DEBUG_OBJECT (video_box, "Alpha value is: %d", i_alpha);
-
-  if (crop_h <= 0 || crop_w <= 0) {
-    oil_splat_u32_ns (destb, &empty_pixel, dblen);
+  GST_DEBUG_OBJECT (video_box, "Alpha value is: %u (frame) %u (border)",
+      i_alpha, b_alpha);
+
+  if (crop_h < 0 || crop_w < 0) {
+    video_box->fill (fill_type, b_alpha, dest, video_box->out_sdtv,
+        video_box->out_width, video_box->out_height, 0, 0, video_box->out_width,
+        video_box->out_height);
+  } else if (bb == 0 && bt == 0 && br == 0 && bl == 0) {
+    video_box->copy (i_alpha, dest, video_box->out_sdtv, video_box->out_width,
+        video_box->out_height, 0, 0, src, video_box->in_sdtv,
+        video_box->in_width, video_box->in_height, 0, 0, crop_w, crop_h);
   } else {
-    const guint32 *src_loc = srcb;
+    gint src_x = 0, src_y = 0;
+    gint dest_x = 0, dest_y = 0;
 
     /* Top border */
     if (bt < 0) {
-      oil_splat_u32_ns (loc, &empty_pixel, (-bt) * video_box->out_width);
-      loc = loc + ((-bt) * video_box->out_width);
+      video_box->fill (fill_type, b_alpha, dest, video_box->out_sdtv,
+          video_box->out_width, video_box->out_height, 0, 0,
+          video_box->out_width, -bt);
+      dest_y += -bt;
     } else {
-      src_loc = src_loc + (bt * video_box->in_width);
-    }
-
-    if (bl >= 0)
-      src_loc += bl;
-
-    for (i = 0; i < crop_h; i++) {
-      gint j;
-
-      /* Left border */
-      if (bl < 0) {
-        oil_splat_u32_ns (loc, &empty_pixel, -bl);
-        loc += (-bl);
-      }
-
-      /* Cropped area */
-      oil_copy_u8 ((guint8 *) loc, (guint8 *) src_loc, crop_w * 4);
-
-      for (j = 0; j < crop_w; j++)
-        gst_video_box_apply_alpha ((guint8 *) & loc[j], i_alpha);
-
-      src_loc += video_box->in_width;
-      loc += crop_w;
-
-      /* Right border */
-      if (br < 0) {
-        oil_splat_u32_ns (loc, &empty_pixel, -br);
-        loc += (-br);
-      }
+      src_y += bt;
     }
 
-    /* Bottom border */
-    if (bb < 0) {
-      oil_splat_u32_ns (loc, &empty_pixel, (-bb) * video_box->out_width);
-    }
-  }
-
-  GST_LOG_OBJECT (video_box, "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, const 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_LOG_OBJECT (video_box, "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_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0,
-      video_box->out_width);
-  Uwidth =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1,
-      video_box->out_width);
-  Vwidth =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2,
-      video_box->out_width);
-
-  Ydest =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
-      video_box->out_width, video_box->out_height);
-  Udest =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
-      video_box->out_width, video_box->out_height);
-  Vdest =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
-      video_box->out_width, video_box->out_height);
-
-  Ysize =
-      Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 0,
-      video_box->out_height);
-  Usize =
-      Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 1,
-      video_box->out_height);
-  Vsize =
-      Ywidth * gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 2,
-      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_malloc0 (Uwidth);
-  Vtemp = g_malloc0 (Vwidth);
-
-  GST_LOG_OBJECT (video_box, "Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt,
-      bb);
-
-  GST_LOG_OBJECT (video_box, "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;
-    const guint32 *src_loc1;
-    gint a = 0;
-
-    src_loc1 = (const 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);
+    /* Left border */
+    if (bl < 0) {
+      video_box->fill (fill_type, b_alpha, dest, video_box->out_sdtv,
+          video_box->out_width, video_box->out_height, 0, dest_y, -bl, crop_h);
+      dest_x += -bl;
     } else {
-      src_loc1 = src_loc1 + (bt * video_box->in_width);
+      src_x += bl;
     }
 
-    if (bl >= 0)
-      src_loc1 += bl;
-
-    GST_LOG_OBJECT (video_box, "Cropped area");
-    GST_LOG_OBJECT (video_box, "Ydest value: %p Ywidth: %u", Ydest, Ywidth);
-    GST_LOG_OBJECT (video_box, "Udest value: %p Uwidth: %u", Udest, Uwidth);
-    GST_LOG_OBJECT (video_box, "Vdest value: %p Vwidth: %u", Vdest, Vwidth);
-    GST_LOG_OBJECT (video_box, "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) {
-          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) {
-          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];
-            Vtemp[UVfloor (a + j)] = ((guint8 *) & src_loc1[j])[3];
-          }
-        }
-        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;
-      }
+    /* Right border */
+    if (br < 0) {
+      video_box->fill (fill_type, b_alpha, dest, video_box->out_sdtv,
+          video_box->out_width, video_box->out_height,
+          video_box->out_width + br, dest_y, -br, crop_h);
     }
 
-    /* bottom border */
+    /* Bottom border */
     if (bb < 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;
-      }
-      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_OBJECT (video_box, "image created");
-  g_free (Utemp);
-  g_free (Vtemp);
-}
-
-static void
-gst_video_box_i420_ayuv (GstVideoBox * video_box, const guint8 * src,
-    guint8 * dest)
-{
-  const guint8 *srcY, *srcU, *srcV;
-  gint crop_width, crop_width2, crop_height;
-  gint out_width, out_height;
-  gint src_stridey, src_strideu, src_stridev;
-  gint br, bl, bt, bb;
-  gint colorY, colorU, colorV;
-  gint i, j;
-  guint8 b_alpha = (guint8) (video_box->border_alpha * 255);
-  guint8 i_alpha = (guint8) (video_box->alpha * 255);
-  guint32 *destp;
-  guint32 *destb = (guint32 *) dest;
-  guint32 ayuv;
-
-  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_stridey =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0,
-      video_box->in_width);
-  src_strideu =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1,
-      video_box->in_width);
-  src_stridev =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2,
-      video_box->in_width);
-
-  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;
-  crop_height -= (video_box->crop_top + video_box->crop_bottom);
-
-  srcY =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
-      video_box->in_width, video_box->in_height);
-  srcY += src_stridey * video_box->crop_top + video_box->crop_left;
-  srcU =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
-      video_box->in_width, video_box->in_height);
-  srcU += src_strideu * (video_box->crop_top / 2) + (video_box->crop_left / 2);
-  srcV =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
-      video_box->in_width, video_box->in_height);
-  srcV += src_stridev * (video_box->crop_top / 2) + (video_box->crop_left / 2);
-
-  colorY = yuv_colors_Y[video_box->fill_type];
-  colorU = yuv_colors_U[video_box->fill_type];
-  colorV = yuv_colors_V[video_box->fill_type];
-
-  ayuv =
-      GUINT32_FROM_BE ((b_alpha << 24) | (colorY << 16) | (colorU << 8) |
-      colorV);
-
-  /* top border */
-  if (bt) {
-    size_t nb_pixels = bt * out_width;
-
-    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);
-      destp += bl;
-    }
-    dest = (guint8 *) destp;
-    /* center */
-    /* We can splat the alpha channel for the whole line */
-    oil_splat_u8 (dest, 4, &i_alpha, crop_width);
-    for (j = 0; j < crop_width2; j++) {
-      dest++;
-      *dest++ = *srcY++;
-      *dest++ = *srcU;
-      *dest++ = *srcV;
-      dest++;
-      *dest++ = *srcY++;
-      *dest++ = *srcU++;
-      *dest++ = *srcV++;
-    }
-    if (i % 2 == 0) {
-      srcU -= crop_width2;
-      srcV -= crop_width2;
-    } else {
-      srcU += src_strideu - crop_width2;
-      srcV += src_stridev - crop_width2;
+      video_box->fill (fill_type, b_alpha, dest, video_box->out_sdtv,
+          video_box->out_width, video_box->out_height, 0, dest_y + crop_h,
+          video_box->out_width, -bb);
     }
-    srcY += src_stridey - (crop_width2 * 2);
 
-    destp = (guint32 *) dest;
-    /* right border */
-    if (br) {
-      oil_splat_u32_ns (destp, &ayuv, br);
-    }
-    destb += out_width;
-  }
-  /* bottom border */
-  if (bb) {
-    size_t nb_pixels = bb * out_width;
-
-    oil_splat_u32_ns (destb, &ayuv, nb_pixels);
+    /* Frame */
+    video_box->copy (i_alpha, dest, video_box->out_sdtv, video_box->out_width,
+        video_box->out_height, dest_x, dest_y, src, video_box->in_sdtv,
+        video_box->in_width, video_box->in_height, src_x, src_y, crop_w,
+        crop_h);
   }
-}
-
-
-static void
-gst_video_box_i420_i420 (GstVideoBox * video_box, const guint8 * src,
-    guint8 * dest)
-{
-  const 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_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, src_width);
-  dest_stride =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, out_width);
-
-  destY =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
-      out_width, out_height);
-
-  srcY =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0,
-      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]);
-
-  br /= 2;
-  bb /= 2;
-  bl /= 2;
-  bt /= 2;
-
-  /* we need to round up to make sure we draw all the U and V lines */
-  crop_width = (crop_width + 1) / 2;
-  crop_height = (crop_height + 1) / 2;
-
-  /* U plane */
-  src_stride =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, src_width);
-  dest_stride =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, out_width);
-
-  destU =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
-      out_width, out_height);
-
-  srcU =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1,
-      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, bl, bt, bb,
-      crop_width, crop_height, src_stride, out_width / 2, dest_stride,
-      yuv_colors_U[video_box->fill_type]);
-
-  /* V plane */
-  src_stride =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, src_width);
-  dest_stride =
-      gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, out_width);
-
-  destV =
-      dest + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
-      out_width, out_height);
-
-  srcV =
-      src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2,
-      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, bl, bt, bb,
-      crop_width, crop_height, src_stride, out_width / 2, dest_stride,
-      yuv_colors_V[video_box->fill_type]);
+  GST_LOG_OBJECT (video_box, "image created");
 }
 
 static GstFlowReturn
@@ -1232,43 +1459,9 @@ gst_video_box_transform (GstBaseTransform * trans, GstBuffer * in,
   outdata = GST_BUFFER_DATA (out);
 
   g_mutex_lock (video_box->mutex);
-  switch (video_box->in_format) {
-    case GST_VIDEO_FORMAT_AYUV:
-      switch (video_box->out_format) {
-        case GST_VIDEO_FORMAT_AYUV:
-          gst_video_box_ayuv_ayuv (video_box, indata, outdata);
-          break;
-        case GST_VIDEO_FORMAT_I420:
-          gst_video_box_ayuv_i420 (video_box, indata, outdata);
-          break;
-        default:
-          goto invalid_format;
-      }
-      break;
-    case GST_VIDEO_FORMAT_I420:
-      switch (video_box->out_format) {
-        case GST_VIDEO_FORMAT_AYUV:
-          gst_video_box_i420_ayuv (video_box, indata, outdata);
-          break;
-        case GST_VIDEO_FORMAT_I420:
-          gst_video_box_i420_i420 (video_box, indata, outdata);
-          break;
-        default:
-          goto invalid_format;
-      }
-      break;
-    default:
-      goto invalid_format;
-  }
+  gst_video_box_process (video_box, indata, outdata);
   g_mutex_unlock (video_box->mutex);
   return GST_FLOW_OK;
-
-  /* ERRORS */
-invalid_format:
-  {
-    g_mutex_unlock (video_box->mutex);
-    return GST_FLOW_ERROR;
-  }
 }
 
 /* FIXME: 0.11 merge with videocrop plugin */
index 9072a6b..6bd15bd 100644 (file)
@@ -58,8 +58,10 @@ struct _GstVideoBox
   /* caps */
   GstVideoFormat in_format;
   gint in_width, in_height;
+  gboolean in_sdtv;
   GstVideoFormat out_format;
   gint out_width, out_height;
+  gboolean out_sdtv;
 
   gint box_left, box_right, box_top, box_bottom;
 
@@ -72,6 +74,9 @@ struct _GstVideoBox
   GstVideoBoxFill fill_type;
 
   gboolean autocrop;
+
+  void (*fill) (GstVideoBoxFill fill_type, guint b_alpha, guint8 *dest, gboolean sdtv, gint width, gint height, gint x, gint y, gint w, gint h);
+  void (*copy) (guint i_alpha, guint8 *dest, gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x, gint dest_y, const guint8 *src, gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y, gint w, gint h);
 };
 
 struct _GstVideoBoxClass