diff options
-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); } } |