From 041ddd6f8f8976cf62be24400ead4904f0f5adfb Mon Sep 17 00:00:00 2001 From: Stephen Jungels Date: Fri, 14 Aug 2009 13:15:57 +0200 Subject: videobox: Add support for autocropping according to the caps Fixes bug #582238. --- gst/videobox/gstvideobox.c | 187 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 147 insertions(+), 40 deletions(-) (limited to 'gst/videobox') diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c index 0cec9357..e58276ac 100644 --- a/gst/videobox/gstvideobox.c +++ b/gst/videobox/gstvideobox.c @@ -35,6 +35,7 @@ * The videobox plugin has many uses such as doing a mosaic of pictures, * letterboxing video, cutting out pieces of video, picture in picture, etc.. */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -90,6 +91,8 @@ struct _GstVideoBox gdouble border_alpha; GstVideoBoxFill fill_type; + + gboolean autocrop; }; struct _GstVideoBoxClass @@ -122,10 +125,30 @@ enum PROP_BOTTOM, PROP_FILL_TYPE, PROP_ALPHA, - PROP_BORDER_ALPHA + PROP_BORDER_ALPHA, + PROP_AUTOCROP /* FILL ME */ }; +/* + +Setting autocrop to true changes the behavior of the plugin so that +caps determine crop properties rather than the other way around: given +input and output dimensions, the crop values are selected so that the +smaller frame is effectively centered in the larger frame. This +involves either cropping or padding. + +If you use autocrop there is little point in setting the other +properties manually because they will be overriden if the caps change, +but nothing stops you from doing so. + +Sample pipeline: +gst-launch videotestsrc ! videobox autocrop=true ! \ +"video/x-raw-yuv, width=600, height=400" ! ffmpegcolorspace ! ximagesink + +*/ + + static GstStaticPadTemplate gst_video_box_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -151,6 +174,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, @@ -233,6 +257,9 @@ gst_video_box_class_init (GstVideoBoxClass * klass) g_param_spec_double ("border_alpha", "Border Alpha", "Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOCROP, + g_param_spec_boolean ("autocrop", "Auto crop", + "Auto crop", FALSE, G_PARAM_READWRITE)); trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform); trans_class->transform_caps = @@ -258,6 +285,7 @@ gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class) video_box->fill_type = DEFAULT_FILL_TYPE; video_box->alpha = DEFAULT_ALPHA; video_box->border_alpha = DEFAULT_BORDER_ALPHA; + video_box->autocrop = FALSE; } static void @@ -317,12 +345,65 @@ gst_video_box_set_property (GObject * object, guint prop_id, case PROP_BORDER_ALPHA: video_box->border_alpha = g_value_get_double (value); break; + case PROP_AUTOCROP: + video_box->autocrop = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } - GST_DEBUG_OBJECT (video_box, "Calling reconfigure"); - gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_box)); + video_box_recalc_transform (video_box); + /* + GST_DEBUG_OBJECT (video_box, "Calling reconfigure"); + gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_box)); + */ + GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box)); +} + +static void +gst_video_box_autocrop (GstVideoBox * video_box) +{ + gint crop_w = (video_box->in_width - video_box->out_width) / 2; + gint crop_h = (video_box->in_height - video_box->out_height) / 2; + + GST_BASE_TRANSFORM_LOCK (GST_BASE_TRANSFORM_CAST (video_box)); + + video_box->box_left = crop_w; + if (video_box->box_left < 0) { + video_box->border_left = -video_box->box_left; + video_box->crop_left = 0; + } else { + video_box->border_left = 0; + video_box->crop_left = video_box->box_left; + } + + video_box->box_right = crop_w; + if (video_box->box_right < 0) { + video_box->border_right = -video_box->box_right; + video_box->crop_right = 0; + } else { + video_box->border_right = 0; + video_box->crop_right = video_box->box_right; + } + + video_box->box_top = crop_h; + if (video_box->box_top < 0) { + video_box->border_top = -video_box->box_top; + video_box->crop_top = 0; + } else { + video_box->border_top = 0; + video_box->crop_top = video_box->box_top; + } + + video_box->box_bottom = crop_h; + if (video_box->box_bottom < 0) { + video_box->border_bottom = -video_box->box_bottom; + video_box->crop_bottom = 0; + } else { + video_box->border_bottom = 0; + video_box->crop_bottom = video_box->box_bottom; + } + GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box)); } @@ -354,6 +435,9 @@ gst_video_box_get_property (GObject * object, guint prop_id, GValue * value, case PROP_BORDER_ALPHA: g_value_set_double (value, video_box->border_alpha); break; + case PROP_AUTOCROP: + g_value_set_boolean (value, video_box->autocrop); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -379,36 +463,45 @@ gst_video_box_transform_caps (GstBaseTransform * trans, /* 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_OBJECT (trans, "New caps width: %d", width); - gst_structure_set (structure, "width", G_TYPE_INT, width, NULL); + /* otherwise caps nego will fail: */ + if (video_box->autocrop) { + gst_structure_remove_field (structure, "width"); + gst_structure_remove_field (structure, "height"); } - 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 (!video_box->autocrop) { + + /* 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_OBJECT (trans, "New caps width: %d", width); + gst_structure_set (structure, "width", G_TYPE_INT, width, NULL); } - if (height <= 0) - height = 1; + 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; + } - GST_DEBUG_OBJECT (trans, "New caps height: %d", height); - gst_structure_set (structure, "height", G_TYPE_INT, height, NULL); + if (height <= 0) + height = 1; + + GST_DEBUG_OBJECT (trans, "New caps height: %d", height); + gst_structure_set (structure, "height", G_TYPE_INT, height, NULL); + } } /* filter against set allowed caps on the pad */ @@ -424,6 +517,26 @@ gst_video_box_transform_caps (GstBaseTransform * trans, 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 any + * 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 gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) { @@ -452,18 +565,11 @@ gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) GST_DEBUG_OBJECT (trans, "Output w: %d h: %d", video_box->out_width, video_box->out_height); - /* 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) { + if (video_box->autocrop) + gst_video_box_autocrop (video_box); - 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); - } + /* recalc the transformation strategy */ + ret = video_box_recalc_transform (video_box); return ret; @@ -947,7 +1053,7 @@ 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; + gint out_width, out_height; gint src_stridey, src_strideu, src_stridev; gint br, bl, bt, bb; gint colorY, colorU, colorV; @@ -964,6 +1070,7 @@ gst_video_box_i420_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest) 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); -- cgit