From 82a509fdfd79dd72f33dd25b02f969e281c5667d Mon Sep 17 00:00:00 2001 From: Dejan Sakelšak Date: Mon, 28 May 2007 15:01:33 +0000 Subject: gst/videobox/gstvideobox.c: Add AYUV->AYUV and AYUV->I420 formats. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message from CVS: Based on patch by: Dejan Sakelšak * 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. --- gst/videobox/gstvideobox.c | 707 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 588 insertions(+), 119 deletions(-) (limited to 'gst/videobox') diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c index 966569b2..5fa3d59e 100644 --- a/gst/videobox/gstvideobox.c +++ b/gst/videobox/gstvideobox.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include @@ -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); } -- cgit