From 82a509fdfd79dd72f33dd25b02f969e281c5667d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dejan=20Sakel=C5=A1ak?= Date: Mon, 28 May 2007 15:01:33 +0000 Subject: [PATCH] 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. --- ChangeLog | 16 + gst/videobox/gstvideobox.c | 801 +++++++++++++++++++++++++++++-------- 2 files changed, 651 insertions(+), 166 deletions(-) diff --git a/ChangeLog b/ChangeLog index cd12c1f151..345df31c54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2007-05-28 Wim Taymans + + 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. + 2007-05-26 Wim Taymans * ext/speex/gstspeexdec.c: (speex_dec_chain_parse_data): diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c index 966569b2ed..5fa3d59e7a 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; + structure = gst_caps_get_structure (to, 0); - 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); + /* 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 (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 (width <= 0) + width = 1; + + GST_DEBUG ("New caps width: %d", width); + gst_structure_set (structure, "width", G_TYPE_INT, width, NULL); } - g_value_unset (&list_value); + 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 (height <= 0) + height = 1; + + GST_DEBUG ("New caps height: %d", height); + gst_structure_set (structure, "height", G_TYPE_INT, height, NULL); + } + + /* 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 to; + return ret; +} + +static gboolean +video_box_recalc_transform (GstVideoBox * video_box) +{ + gboolean res = TRUE; + + /* 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,7 +547,504 @@ 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) +{ + if (dest[0] != 0) + dest[0] = alpha; +} + +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; + } + + 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; + } + + GST_DEBUG ("Borders are: L:%d, R:%d, T:%d, B:%d", bl, br, bt, bb); + GST_DEBUG ("Alpha value is: %d", i_alpha); + + if (crop_h <= 0 || crop_w <= 0) { + + oil_splat_u32_ns (destb, &empty_pixel, dblen); + + } else { + + guint32 *src_loc = srcb; + + /* 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); + } + + 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); + } + } + + /* 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); +} + +static void +gst_video_box_i420_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest) +{ + 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_I420_Y_ROWSTRIDE (video_box->in_width); + 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; + 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_I420_Y_OFFSET (video_box->in_width, video_box->in_height); + srcY += src_stridey * video_box->crop_top + video_box->crop_left; + srcU = + src + GST_VIDEO_I420_U_OFFSET (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_I420_V_OFFSET (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; + } + srcY += src_stridey - (crop_width2 * 2); + + destp = (guint32 *) dest; + /* right border */ + if (br) { + 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 (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; @@ -565,132 +1108,58 @@ gst_video_box_i420 (GstVideoBox * video_box, guint8 * src, guint8 * dest) dest_stride, yuv_colors_V[video_box->fill_type]); } -/* 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) -{ - 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 *) 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_I420_Y_ROWSTRIDE (video_box->in_width); - 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_width2 = crop_width / 2; - crop_height = - video_box->in_height - (video_box->crop_top + video_box->crop_bottom); - - srcY = - src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height); - srcY += src_stridey * video_box->crop_top + video_box->crop_left; - srcU = - src + GST_VIDEO_I420_U_OFFSET (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_I420_V_OFFSET (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 (destp, &ayuv, nb_pixels); - destp += nb_pixels; - } - for (i = 0; i < crop_height; i++) { - /* 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; - } - srcY += src_stridey - crop_width; - - destp = (guint32 *) dest; - /* right border */ - if (br) { - oil_splat_u32_ns (destp, &ayuv, br); - destp += br; - } - } - /* bottom border */ - if (bb) { - size_t nb_pixels = bb * out_width; - - oil_splat_u32_ns (destp, &ayuv, nb_pixels); - destp += nb_pixels; - } -} - 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); }