mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 00:36:51 +00:00
v4l2src: Add support for cropping at capture source input
Add properties to control input cropping in the V4L2 device. The input cropping is applied before composing the result to the capture buffer. By default the capture size will be set to the same size as the crop region, but it can be scaled to a different output frame size if supported by the V4L2 device. If scaling is not supported, the cropped image will be composed as is into the top-left corner of the capture buffer. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1089>
This commit is contained in:
parent
ceff3e8ff7
commit
70086fda22
2 changed files with 209 additions and 0 deletions
|
@ -72,6 +72,11 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
V4L2_STD_OBJECT_PROPS,
|
||||
PROP_CROP_TOP,
|
||||
PROP_CROP_LEFT,
|
||||
PROP_CROP_BOTTOM,
|
||||
PROP_CROP_RIGHT,
|
||||
PROP_CROP_BOUNDS,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -157,6 +162,81 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
|
|||
gst_v4l2_object_install_properties_helper (gobject_class,
|
||||
DEFAULT_PROP_DEVICE);
|
||||
|
||||
/**
|
||||
* GstV4l2Src:crop-top:
|
||||
*
|
||||
* Number of pixels to crop from the top edge of captured video
|
||||
* stream
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CROP_TOP,
|
||||
g_param_spec_uint ("crop-top", "Crop top",
|
||||
"Pixels to crop at top of video capture input",
|
||||
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Src:crop-left:
|
||||
*
|
||||
* Number of pixels to crop from the left edge of captured video
|
||||
* stream
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CROP_LEFT,
|
||||
g_param_spec_uint ("crop-left", "Crop left",
|
||||
"Pixels to crop at left of video capture input",
|
||||
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Src:crop-bottom:
|
||||
*
|
||||
* Number of pixels to crop from the bottom edge of captured video
|
||||
* stream
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CROP_BOTTOM,
|
||||
g_param_spec_uint ("crop-bottom", "Crop bottom",
|
||||
"Pixels to crop at bottom of video capture input",
|
||||
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Src:crop-right:
|
||||
*
|
||||
* Number of pixels to crop from the right edge of captured video
|
||||
* stream
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CROP_RIGHT,
|
||||
g_param_spec_uint ("crop-right", "Crop right",
|
||||
"Pixels to crop at right of video capture input",
|
||||
0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Src:crop-bounds:
|
||||
*
|
||||
* Crop bounding region. All crop regions must lie within this region.
|
||||
* The bounds are represented as a four element array, that descibes the
|
||||
* [x, y, width, height] of the area.
|
||||
*
|
||||
* The size and position of the crop
|
||||
* bounds will only be known, once the v4l2 device is opened and the
|
||||
* input source selected. Applications can connect to the
|
||||
* "notify::crop-bounds" signal to be notified when the bounding region is
|
||||
* updated, and set an appropriate crop region.
|
||||
*
|
||||
* Since: 1.22
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CROP_BOUNDS,
|
||||
gst_param_spec_array ("crop-bounds", "Crop bounds",
|
||||
"The bounding region for crop rectangles ('<x, y, width, height>').",
|
||||
g_param_spec_int ("rect-value", "Rectangle Value",
|
||||
"One of x, y, width or height value.", G_MININT, G_MAXINT, -1,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS),
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Src::prepare-format:
|
||||
* @v4l2src: the v4l2src instance
|
||||
|
@ -236,6 +316,18 @@ gst_v4l2src_set_property (GObject * object,
|
|||
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
|
||||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_CROP_TOP:
|
||||
v4l2src->crop_top = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_CROP_LEFT:
|
||||
v4l2src->crop_left = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_CROP_BOTTOM:
|
||||
v4l2src->crop_bottom = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_CROP_RIGHT:
|
||||
v4l2src->crop_right = g_value_get_uint (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -243,6 +335,29 @@ gst_v4l2src_set_property (GObject * object,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2src_set_rect_value (GValue * value, struct v4l2_rect *rect)
|
||||
{
|
||||
GValue val = { 0 };
|
||||
|
||||
g_value_init (&val, G_TYPE_INT);
|
||||
g_value_reset (value);
|
||||
|
||||
g_value_set_int (&val, rect->left);
|
||||
gst_value_array_append_value (value, &val);
|
||||
|
||||
g_value_set_int (&val, rect->top);
|
||||
gst_value_array_append_value (value, &val);
|
||||
|
||||
g_value_set_int (&val, rect->width);
|
||||
gst_value_array_append_value (value, &val);
|
||||
|
||||
g_value_set_int (&val, rect->height);
|
||||
gst_value_array_append_value (value, &val);
|
||||
|
||||
g_value_unset (&val);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2src_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec)
|
||||
|
@ -252,6 +367,21 @@ gst_v4l2src_get_property (GObject * object,
|
|||
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
|
||||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_CROP_TOP:
|
||||
g_value_set_uint (value, v4l2src->crop_top);
|
||||
break;
|
||||
case PROP_CROP_LEFT:
|
||||
g_value_set_uint (value, v4l2src->crop_left);
|
||||
break;
|
||||
case PROP_CROP_BOTTOM:
|
||||
g_value_set_uint (value, v4l2src->crop_bottom);
|
||||
break;
|
||||
case PROP_CROP_RIGHT:
|
||||
g_value_set_uint (value, v4l2src->crop_right);
|
||||
break;
|
||||
case PROP_CROP_BOUNDS:
|
||||
gst_v4l2src_set_rect_value (value, &v4l2src->crop_bounds);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -373,6 +503,23 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_do_source_crop (GstV4l2Src * v4l2src)
|
||||
{
|
||||
struct v4l2_rect def_crop;
|
||||
|
||||
if (v4l2src->apply_crop_settings)
|
||||
return gst_v4l2_object_set_crop (v4l2src->v4l2object, &v4l2src->crop_rect);
|
||||
|
||||
/* If no crop setting is given, reset to the default. Resetting the default
|
||||
* crop may fail if the device does not support cropping. This should not
|
||||
* be considered an error. */
|
||||
if (gst_v4l2_object_get_crop_default (v4l2src->v4l2object, &def_crop))
|
||||
gst_v4l2_object_set_crop (v4l2src->v4l2object, &def_crop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_set_format (GstV4l2Src * v4l2src, GstCaps * caps,
|
||||
GstV4l2Error * error)
|
||||
|
@ -388,6 +535,9 @@ gst_v4l2src_set_format (GstV4l2Src * v4l2src, GstCaps * caps,
|
|||
g_signal_emit (v4l2src, gst_v4l2_signals[SIGNAL_PRE_SET_FORMAT], 0,
|
||||
v4l2src->v4l2object->video_fd, caps);
|
||||
|
||||
if (!gst_v4l2src_do_source_crop (v4l2src))
|
||||
return FALSE;
|
||||
|
||||
return gst_v4l2_object_set_format (obj, caps, error);
|
||||
}
|
||||
|
||||
|
@ -576,6 +726,53 @@ gst_v4l2src_query_preferred_size (GstV4l2Src * v4l2src,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_setup_source_crop (GstV4l2Src * v4l2src,
|
||||
struct PreferredCapsInfo *pref)
|
||||
{
|
||||
gint cropped_width, cropped_height;
|
||||
struct v4l2_rect *crop_bounds = &v4l2src->crop_bounds;
|
||||
|
||||
v4l2src->apply_crop_settings = FALSE;
|
||||
|
||||
if (!gst_v4l2_object_get_crop_bounds (v4l2src->v4l2object, crop_bounds))
|
||||
return FALSE;
|
||||
|
||||
g_object_notify (G_OBJECT (v4l2src), "crop-bounds");
|
||||
|
||||
cropped_width = crop_bounds->width - v4l2src->crop_left - v4l2src->crop_right;
|
||||
cropped_height =
|
||||
crop_bounds->height - v4l2src->crop_top - v4l2src->crop_bottom;
|
||||
|
||||
if (v4l2src->crop_left < crop_bounds->left
|
||||
|| v4l2src->crop_top < crop_bounds->top
|
||||
|| cropped_width <= 0 || cropped_height <= 0) {
|
||||
GST_WARNING_OBJECT (v4l2src, "Ignoring out of bounds crop region");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (cropped_width == crop_bounds->width
|
||||
&& cropped_height == crop_bounds->height) {
|
||||
GST_DEBUG_OBJECT (v4l2src,
|
||||
"No cropping requested, keep current preferred size");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
v4l2src->crop_rect.left = v4l2src->crop_left;
|
||||
v4l2src->crop_rect.top = v4l2src->crop_top;
|
||||
v4l2src->crop_rect.width = cropped_width;
|
||||
v4l2src->crop_rect.height = cropped_height;
|
||||
v4l2src->apply_crop_settings = TRUE;
|
||||
|
||||
pref->width = cropped_width;
|
||||
pref->height = cropped_height;
|
||||
|
||||
GST_INFO_OBJECT (v4l2src, "Updated preferred capture size to %i x %i",
|
||||
pref->width, pref->height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_negotiate (GstBaseSrc * basesrc)
|
||||
{
|
||||
|
@ -596,6 +793,8 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
|
|||
* the caps enumeration. */
|
||||
have_pref = gst_v4l2src_query_preferred_size (v4l2src, &pref);
|
||||
|
||||
have_pref |= gst_v4l2src_setup_source_crop (v4l2src, &pref);
|
||||
|
||||
/* first see what is possible on our source pad */
|
||||
thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
|
||||
GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
|
||||
|
|
|
@ -65,6 +65,16 @@ struct _GstV4l2Src
|
|||
|
||||
gboolean pending_set_fmt;
|
||||
|
||||
guint crop_top;
|
||||
guint crop_left;
|
||||
guint crop_bottom;
|
||||
guint crop_right;
|
||||
|
||||
struct v4l2_rect crop_bounds;
|
||||
|
||||
gboolean apply_crop_settings;
|
||||
struct v4l2_rect crop_rect;
|
||||
|
||||
/* Timestamp sanity check */
|
||||
GstClockTime last_timestamp;
|
||||
gboolean has_bad_timestamp;
|
||||
|
|
Loading…
Reference in a new issue