diff options
author | Nicolas Dufresne <nicolas.dufresne@collabora.com> | 2012-11-06 11:53:25 +0100 |
---|---|---|
committer | Olivier CrĂȘte <olivier.crete@collabora.com> | 2012-11-07 11:17:26 +0100 |
commit | 42ec3552f2dfd77e0e83663369e78838c0463ab6 (patch) | |
tree | 70c11a4311879d77eba6bae15c09ac007511bf1d | |
parent | 73a478b02fcb71e2fe9ed104fa2b1125b84c5460 (diff) |
videocrop: Add support for automatic cropping
This change enable automatic cropping using -1 set to left, top, right or
bottom property. In the case both side are set to automatic cropping, the
croping will be done equally on both side (in the odd case, right and
bottom cropping will be 1 pixel more).
https://bugzilla.gnome.org/show_bug.cgi?id=687655
-rw-r--r-- | gst/videocrop/gstvideocrop.c | 159 | ||||
-rw-r--r-- | gst/videocrop/gstvideocrop.h | 5 | ||||
-rw-r--r-- | tests/check/elements/videocrop.c | 92 |
3 files changed, 190 insertions, 66 deletions
diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 14c7bac25..082ca1184 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -210,17 +210,21 @@ gst_video_crop_class_init (GstVideoCropClass * klass) gobject_class->get_property = gst_video_crop_get_property; g_object_class_install_property (gobject_class, ARG_LEFT, - g_param_spec_int ("left", "Left", "Pixels to crop at left", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("left", "Left", + "Pixels to crop at left (-1 to auto-crop)", -1, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, ARG_RIGHT, - g_param_spec_int ("right", "Right", "Pixels to crop at right", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("right", "Right", + "Pixels to crop at right (-1 to auto-crop)", -1, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, ARG_TOP, - g_param_spec_int ("top", "Top", "Pixels to crop at top", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("top", "Top", + "Pixels to crop at top (-1 to auto-crop)", -1, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, ARG_BOTTOM, - g_param_spec_int ("bottom", "Bottom", "Pixels to crop at bottom", - 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_param_spec_int ("bottom", "Bottom", + "Pixels to crop at bottom (-1 to auto-crop)", -1, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); basetransform_class->transform = GST_DEBUG_FUNCPTR (gst_video_crop_transform); basetransform_class->transform_caps = @@ -236,6 +240,10 @@ gst_video_crop_class_init (GstVideoCropClass * klass) static void gst_video_crop_init (GstVideoCrop * vcrop, GstVideoCropClass * klass) { + vcrop->prop_right = 0; + vcrop->prop_left = 0; + vcrop->prop_top = 0; + vcrop->prop_bottom = 0; vcrop->crop_right = 0; vcrop->crop_left = 0; vcrop->crop_top = 0; @@ -507,33 +515,69 @@ gst_video_crop_transform_dimension (gint val, gint delta) static gboolean gst_video_crop_transform_dimension_value (const GValue * src_val, - gint delta, GValue * dest_val) + gint delta, GValue * dest_val, GstPadDirection direction, gboolean dynamic) { gboolean ret = TRUE; - g_value_init (dest_val, G_VALUE_TYPE (src_val)); - if (G_VALUE_HOLDS_INT (src_val)) { gint ival = g_value_get_int (src_val); - ival = gst_video_crop_transform_dimension (ival, delta); - g_value_set_int (dest_val, ival); + + if (dynamic) { + if (direction == GST_PAD_SRC) { + if (ival == G_MAXINT) { + g_value_init (dest_val, G_TYPE_INT); + g_value_set_int (dest_val, ival); + } else { + g_value_init (dest_val, GST_TYPE_INT_RANGE); + gst_value_set_int_range (dest_val, ival, G_MAXINT); + } + } else { + if (ival == 1) { + g_value_init (dest_val, G_TYPE_INT); + g_value_set_int (dest_val, ival); + } else { + g_value_init (dest_val, GST_TYPE_INT_RANGE); + gst_value_set_int_range (dest_val, 1, ival); + } + } + } else { + g_value_init (dest_val, G_TYPE_INT); + g_value_set_int (dest_val, ival); + } } else if (GST_VALUE_HOLDS_INT_RANGE (src_val)) { gint min = gst_value_get_int_range_min (src_val); gint max = gst_value_get_int_range_max (src_val); min = gst_video_crop_transform_dimension (min, delta); max = gst_video_crop_transform_dimension (max, delta); - gst_value_set_int_range (dest_val, min, max); + + if (dynamic) { + if (direction == GST_PAD_SRC) + max = G_MAXINT; + else + min = 1; + } + + if (min == max) { + g_value_init (dest_val, G_TYPE_INT); + g_value_set_int (dest_val, min); + } else { + g_value_init (dest_val, GST_TYPE_INT_RANGE); + gst_value_set_int_range (dest_val, min, max); + } } else if (GST_VALUE_HOLDS_LIST (src_val)) { gint i; + g_value_init (dest_val, GST_TYPE_LIST); + for (i = 0; i < gst_value_list_get_size (src_val); ++i) { const GValue *list_val; GValue newval = { 0, }; list_val = gst_value_list_get_value (src_val, i); - if (gst_video_crop_transform_dimension_value (list_val, delta, &newval)) + if (gst_video_crop_transform_dimension_value (list_val, delta, &newval, + direction, dynamic)) gst_value_list_append_value (dest_val, &newval); g_value_unset (&newval); } @@ -543,7 +587,6 @@ gst_video_crop_transform_dimension_value (const GValue * src_val, ret = FALSE; } } else { - g_value_unset (dest_val); ret = FALSE; } @@ -556,21 +599,30 @@ gst_video_crop_transform_caps (GstBaseTransform * trans, { GstVideoCrop *vcrop; GstCaps *other_caps; - gint dy, dx, i; + gint dy, dx, i, left, right, bottom, top; + gboolean w_dynamic, h_dynamic; vcrop = GST_VIDEO_CROP (trans); GST_OBJECT_LOCK (vcrop); GST_LOG_OBJECT (vcrop, "l=%d,r=%d,b=%d,t=%d", - vcrop->crop_left, vcrop->crop_right, vcrop->crop_bottom, vcrop->crop_top); + vcrop->prop_left, vcrop->prop_right, vcrop->prop_bottom, vcrop->prop_top); + + w_dynamic = (vcrop->prop_left == -1 || vcrop->prop_right == -1); + h_dynamic = (vcrop->prop_top == -1 || vcrop->prop_bottom == -1); + + left = (vcrop->prop_left == -1) ? 0 : vcrop->prop_left; + right = (vcrop->prop_right == -1) ? 0 : vcrop->prop_right; + bottom = (vcrop->prop_bottom == -1) ? 0 : vcrop->prop_bottom; + top = (vcrop->prop_top == -1) ? 0 : vcrop->prop_top; if (direction == GST_PAD_SRC) { - dx = vcrop->crop_left + vcrop->crop_right; - dy = vcrop->crop_top + vcrop->crop_bottom; + dx = left + right; + dy = top + bottom; } else { - dx = 0 - (vcrop->crop_left + vcrop->crop_right); - dy = 0 - (vcrop->crop_top + vcrop->crop_bottom); + dx = 0 - (left + right); + dy = 0 - (top + bottom); } GST_OBJECT_UNLOCK (vcrop); @@ -587,14 +639,16 @@ gst_video_crop_transform_caps (GstBaseTransform * trans, structure = gst_caps_get_structure (caps, i); v = gst_structure_get_value (structure, "width"); - if (!gst_video_crop_transform_dimension_value (v, dx, &w_val)) { + if (!gst_video_crop_transform_dimension_value (v, dx, &w_val, direction, + w_dynamic)) { GST_WARNING_OBJECT (vcrop, "could not tranform width value with dx=%d" ", caps structure=%" GST_PTR_FORMAT, dx, structure); continue; } v = gst_structure_get_value (structure, "height"); - if (!gst_video_crop_transform_dimension_value (v, dy, &h_val)) { + if (!gst_video_crop_transform_dimension_value (v, dy, &h_val, direction, + h_dynamic)) { g_value_unset (&w_val); GST_WARNING_OBJECT (vcrop, "could not tranform height value with dy=%d" ", caps structure=%" GST_PTR_FORMAT, dy, structure); @@ -624,6 +678,7 @@ gst_video_crop_set_caps (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) { GstVideoCrop *crop = GST_VIDEO_CROP (trans); + int dx, dy; if (!gst_video_crop_get_image_details_from_caps (crop, &crop->in, incaps)) goto wrong_input; @@ -631,6 +686,40 @@ gst_video_crop_set_caps (GstBaseTransform * trans, GstCaps * incaps, if (!gst_video_crop_get_image_details_from_caps (crop, &crop->out, outcaps)) goto wrong_output; + crop->crop_left = crop->prop_left; + crop->crop_right = crop->prop_right; + crop->crop_top = crop->prop_top; + crop->crop_bottom = crop->prop_bottom; + + dx = crop->in.width - crop->out.width; + dy = crop->in.height - crop->out.height; + + if (crop->prop_left == -1 && crop->prop_right == -1) { + crop->crop_left = dx / 2; + crop->crop_right = dx / 2 + (dx & 1); + } else if (crop->prop_left == -1) { + if (G_UNLIKELY (crop->prop_right > dx)) + goto cropping_too_much; + crop->crop_left = dx - crop->prop_right; + } else if (crop->prop_right == -1) { + if (G_UNLIKELY (crop->prop_left > dx)) + goto cropping_too_much; + crop->crop_right = dx - crop->prop_left; + } + + if (crop->prop_top == -1 && crop->prop_bottom == -1) { + crop->crop_top = dy / 2; + crop->crop_bottom = dy / 2 + (dy & 1); + } else if (crop->prop_top == -1) { + if (G_UNLIKELY (crop->prop_bottom > dy)) + goto cropping_too_much; + crop->crop_top = dy - crop->prop_bottom; + } else if (crop->prop_bottom == -1) { + if (G_UNLIKELY (crop->prop_top > dy)) + goto cropping_too_much; + crop->crop_bottom = dy - crop->prop_top; + } + if (G_UNLIKELY ((crop->crop_left + crop->crop_right) >= crop->in.width || (crop->crop_top + crop->crop_bottom) >= crop->in.height)) goto cropping_too_much; @@ -652,19 +741,19 @@ gst_video_crop_set_caps (GstBaseTransform * trans, GstCaps * incaps, /* ERROR */ wrong_input: { - GST_DEBUG_OBJECT (crop, "failed to parse input caps %" GST_PTR_FORMAT, + GST_WARNING_OBJECT (crop, "failed to parse input caps %" GST_PTR_FORMAT, incaps); return FALSE; } wrong_output: { - GST_DEBUG_OBJECT (crop, "failed to parse output caps %" GST_PTR_FORMAT, + GST_WARNING_OBJECT (crop, "failed to parse output caps %" GST_PTR_FORMAT, outcaps); return FALSE; } cropping_too_much: { - GST_DEBUG_OBJECT (crop, "we are cropping too much"); + GST_WARNING_OBJECT (crop, "we are cropping too much"); return FALSE; } } @@ -684,16 +773,16 @@ gst_video_crop_set_property (GObject * object, guint prop_id, GST_OBJECT_LOCK (video_crop); switch (prop_id) { case ARG_LEFT: - video_crop->crop_left = g_value_get_int (value); + video_crop->prop_left = g_value_get_int (value); break; case ARG_RIGHT: - video_crop->crop_right = g_value_get_int (value); + video_crop->prop_right = g_value_get_int (value); break; case ARG_TOP: - video_crop->crop_top = g_value_get_int (value); + video_crop->prop_top = g_value_get_int (value); break; case ARG_BOTTOM: - video_crop->crop_bottom = g_value_get_int (value); + video_crop->prop_bottom = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -720,16 +809,16 @@ gst_video_crop_get_property (GObject * object, guint prop_id, GValue * value, GST_OBJECT_LOCK (video_crop); switch (prop_id) { case ARG_LEFT: - g_value_set_int (value, video_crop->crop_left); + g_value_set_int (value, video_crop->prop_left); break; case ARG_RIGHT: - g_value_set_int (value, video_crop->crop_right); + g_value_set_int (value, video_crop->prop_right); break; case ARG_TOP: - g_value_set_int (value, video_crop->crop_top); + g_value_set_int (value, video_crop->prop_top); break; case ARG_BOTTOM: - g_value_set_int (value, video_crop->crop_bottom); + g_value_set_int (value, video_crop->prop_bottom); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/gst/videocrop/gstvideocrop.h b/gst/videocrop/gstvideocrop.h index 477f21b06..d13ca9b2d 100644 --- a/gst/videocrop/gstvideocrop.h +++ b/gst/videocrop/gstvideocrop.h @@ -70,6 +70,11 @@ struct _GstVideoCrop GstBaseTransform basetransform; /*< private >*/ + gint prop_left; + gint prop_right; + gint prop_top; + gint prop_bottom; + gint crop_left; gint crop_right; gint crop_top; diff --git a/tests/check/elements/videocrop.c b/tests/check/elements/videocrop.c index fc7c5dc14..9f68e9575 100644 --- a/tests/check/elements/videocrop.c +++ b/tests/check/elements/videocrop.c @@ -155,6 +155,7 @@ typedef struct GstElement *src; GstElement *filter; GstElement *crop; + GstElement *filter2; GstElement *sink; GstBuffer *last_buf; } GstVideoCropTestContext; @@ -179,12 +180,16 @@ videocrop_test_cropping_init_context (GstVideoCropTestContext * ctx) fail_unless (ctx->filter != NULL, "Failed to create capsfilter element"); ctx->crop = gst_element_factory_make ("videocrop", "crop"); fail_unless (ctx->crop != NULL, "Failed to create videocrop element"); + ctx->filter2 = gst_element_factory_make ("capsfilter", "filter2"); + fail_unless (ctx->filter2 != NULL, + "Failed to create second capsfilter element"); ctx->sink = gst_element_factory_make ("fakesink", "sink"); fail_unless (ctx->sink != NULL, "Failed to create fakesink element"); gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->src, ctx->filter, - ctx->crop, ctx->sink, NULL); - gst_element_link_many (ctx->src, ctx->filter, ctx->crop, ctx->sink, NULL); + ctx->crop, ctx->filter2, ctx->sink, NULL); + gst_element_link_many (ctx->src, ctx->filter, ctx->crop, ctx->filter2, + ctx->sink, NULL); /* set pattern to 'red' - for our purposes it doesn't matter anyway */ g_object_set (ctx->src, "pattern", 4, NULL); @@ -213,13 +218,15 @@ typedef void (*GstVideoCropTestBufferFunc) (GstBuffer * buffer); static void videocrop_test_cropping (GstVideoCropTestContext * ctx, GstCaps * in_caps, - gint left, gint right, gint top, gint bottom, + GstCaps * out_caps, gint left, gint right, gint top, gint bottom, GstVideoCropTestBufferFunc func) { - GST_LOG ("lrtb = %03u %03u %03u %03u, caps = %" GST_PTR_FORMAT, left, right, - top, bottom, in_caps); + GST_LOG ("lrtb = %03u %03u %03u %03u, in_caps = %" GST_PTR_FORMAT + ", out_caps = %" GST_PTR_FORMAT, left, right, top, bottom, in_caps, + out_caps); g_object_set (ctx->filter, "caps", in_caps, NULL); + g_object_set (ctx->filter2, "caps", out_caps, NULL); g_object_set (ctx->crop, "left", left, "right", right, "top", top, "bottom", bottom, NULL); @@ -359,11 +366,12 @@ GST_START_TEST (test_crop_to_1x1) gst_structure_set (s, "width", G_TYPE_INT, 160, "height", G_TYPE_INT, 160, NULL); - videocrop_test_cropping (&ctx, caps, 159, 0, 159, 0, check_1x1_buffer); + videocrop_test_cropping (&ctx, caps, NULL, 159, 0, 159, 0, + check_1x1_buffer); /* commented out because they don't really add anything useful check-wise: - videocrop_test_cropping (&ctx, caps, 0, 159, 0, 159, check_1x1_buffer); - videocrop_test_cropping (&ctx, caps, 159, 0, 0, 159, check_1x1_buffer); - videocrop_test_cropping (&ctx, caps, 0, 159, 159, 0, check_1x1_buffer); + videocrop_test_cropping (&ctx, caps, NULL, 0, 159, 0, 159, check_1x1_buffer); + videocrop_test_cropping (&ctx, caps, NULL, 159, 0, 0, 159, check_1x1_buffer); + videocrop_test_cropping (&ctx, caps, NULL, 0, 159, 159, 0, check_1x1_buffer); */ gst_caps_unref (caps); } @@ -413,7 +421,7 @@ GST_START_TEST (test_cropping) GST_INFO ("testing format: %" GST_PTR_FORMAT, caps); for (i = 0; i < G_N_ELEMENTS (sizes_to_try); ++i) { - GstCaps *in_caps; + GstCaps *in_caps, *out_caps; GST_INFO (" - %d x %d", sizes_to_try[i].width, sizes_to_try[i].height); @@ -421,29 +429,51 @@ GST_START_TEST (test_cropping) "height", G_TYPE_INT, sizes_to_try[i].height, NULL); in_caps = gst_caps_copy (caps); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 1, 0, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 1, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 1, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 0, 1, NULL); - videocrop_test_cropping (&ctx, in_caps, 63, 0, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 63, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 63, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 0, 63, NULL); - videocrop_test_cropping (&ctx, in_caps, 63, 0, 0, 1, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 63, 1, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 1, 63, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 1, 0, 0, 63, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 0, 0, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 32, 0, 0, 128, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 32, 128, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 0, 128, 32, 0, NULL); - videocrop_test_cropping (&ctx, in_caps, 128, 0, 0, 32, NULL); - videocrop_test_cropping (&ctx, in_caps, 1, 1, 1, 1, NULL); - videocrop_test_cropping (&ctx, in_caps, 63, 63, 63, 63, NULL); - videocrop_test_cropping (&ctx, in_caps, 64, 64, 64, 64, NULL); + gst_structure_set (s, "width", G_TYPE_INT, 1, "height", G_TYPE_INT, 1, + NULL); + out_caps = gst_caps_copy (caps); + + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 1, 0, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 1, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 1, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 1, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 63, 0, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 63, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 63, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 63, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 63, 0, 0, 1, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 63, 1, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 1, 63, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 1, 0, 0, 63, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 0, 0, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 32, 0, 0, 128, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 32, 128, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 0, 128, 32, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 128, 0, 0, 32, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 1, 1, 1, 1, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 63, 63, 63, 63, NULL); + videocrop_test_cropping (&ctx, in_caps, NULL, 64, 64, 64, 64, NULL); + + /* Dynamic cropping */ + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, 0, -1, -1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, 0, -1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, 0, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1, 0, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, 10, -1, 10, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, 10, -1, 10, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, + sizes_to_try[i].width - 1, -1, -1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, + sizes_to_try[i].width - 1, -1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, + sizes_to_try[i].height - 1, -1, NULL); + videocrop_test_cropping (&ctx, in_caps, out_caps, -1, -1, -1, + sizes_to_try[i].height - 1, NULL); gst_caps_unref (in_caps); + gst_caps_unref (out_caps); } } |