mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-05-22 10:18:31 +00:00
Merge branch 'dev-selection' into 'main'
v4l2transform: add property to configure crop/compose See merge request gstreamer/gstreamer!5050
This commit is contained in:
commit
85a96a9b25
|
@ -4682,6 +4682,61 @@ unsupported_format:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_v4l2_object_set_compose:
|
||||
* @obj: the object
|
||||
* @compose_rect: the region to compose
|
||||
*
|
||||
* Compose the video data to the regions specified in the @compose_rect.
|
||||
*
|
||||
* For capture devices, this compose the image sensor / video stream provided by
|
||||
* the V4L2 device. The composing area specifies which part of the buffer is
|
||||
* actually written to by the hardware.
|
||||
* For output devices, this compose the memory buffer that GStreamer passed to
|
||||
* the V4L2 device. The application may select the part of display where the
|
||||
* image should be displayed. The size and position of such a window is
|
||||
* controlled by the compose target.
|
||||
*
|
||||
* The compose_rect may be modified by the V4L2 device to a region that
|
||||
* fulfills H/W requirements.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on failure.
|
||||
*/
|
||||
gboolean
|
||||
gst_v4l2_object_set_compose (GstV4l2Object * obj,
|
||||
struct v4l2_rect *compose_rect)
|
||||
{
|
||||
struct v4l2_selection sel = { 0 };
|
||||
|
||||
GST_V4L2_CHECK_OPEN (obj);
|
||||
|
||||
sel.type = obj->type;
|
||||
sel.target = V4L2_SEL_TGT_COMPOSE;
|
||||
sel.flags = 0;
|
||||
sel.r = *compose_rect;
|
||||
|
||||
GST_DEBUG_OBJECT (obj->dbg_obj,
|
||||
"Desired composing left %u, top %u, size %ux%u", sel.r.left, sel.r.top,
|
||||
sel.r.width, sel.r.height);
|
||||
|
||||
if (obj->ioctl (obj->video_fd, VIDIOC_S_SELECTION, &sel) < 0) {
|
||||
if (errno != ENOTTY) {
|
||||
GST_WARNING_OBJECT (obj->dbg_obj,
|
||||
"Failed to set compose rectangle with VIDIOC_S_SELECTION: %s",
|
||||
g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (obj->dbg_obj,
|
||||
"Got composing left %u, top %u, size %ux%u", sel.r.left, sel.r.top,
|
||||
sel.r.width, sel.r.height);
|
||||
|
||||
*compose_rect = sel.r;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_v4l2_object_set_crop:
|
||||
* @obj: the object
|
||||
|
|
|
@ -332,6 +332,7 @@ gboolean gst_v4l2_object_is_raw (GstV4l2Object * obj);
|
|||
gboolean gst_v4l2_object_set_crop (GstV4l2Object * obj, struct v4l2_rect *result);
|
||||
gboolean gst_v4l2_object_get_crop_bounds (GstV4l2Object * obj, struct v4l2_rect *bounds);
|
||||
gboolean gst_v4l2_object_get_crop_default (GstV4l2Object * obj, struct v4l2_rect *bounds);
|
||||
gboolean gst_v4l2_object_set_compose (GstV4l2Object * obj, struct v4l2_rect *compose_rect);
|
||||
|
||||
/* TODO Move to proper namespace */
|
||||
/* open/close the device */
|
||||
|
|
|
@ -48,7 +48,8 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
V4L2_STD_OBJECT_PROPS,
|
||||
PROP_DISABLE_PASSTHROUGH
|
||||
PROP_DISABLE_PASSTHROUGH,
|
||||
PROP_SELECTION_TARGETS,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -62,6 +63,150 @@ typedef struct
|
|||
G_DEFINE_ABSTRACT_TYPE (GstV4l2Transform, gst_v4l2_transform,
|
||||
GST_TYPE_BASE_TRANSFORM);
|
||||
|
||||
static void
|
||||
gst_v4l2_transform_selection_targets_apply (GstV4l2Transform * self)
|
||||
{
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
|
||||
if (self->selection_targets.compose_capture_need_config == TRUE) {
|
||||
struct v4l2_rect rect = {
|
||||
.left = self->selection_targets.compose_capture_rect.x,
|
||||
.top = self->selection_targets.compose_capture_rect.y,
|
||||
.width = self->selection_targets.compose_capture_rect.w,
|
||||
.height = self->selection_targets.compose_capture_rect.h,
|
||||
};
|
||||
|
||||
gst_v4l2_object_set_compose (self->v4l2capture, &rect);
|
||||
|
||||
self->selection_targets.compose_capture_need_config = FALSE;
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Configure compose for capture. left/top/width/height: %d %d %u %u",
|
||||
rect.left, rect.top, rect.width, rect.height);
|
||||
}
|
||||
|
||||
if (self->selection_targets.crop_capture_need_config == TRUE) {
|
||||
struct v4l2_rect rect = {
|
||||
.left = self->selection_targets.crop_capture_rect.x,
|
||||
.top = self->selection_targets.crop_capture_rect.y,
|
||||
.width = self->selection_targets.crop_capture_rect.w,
|
||||
.height = self->selection_targets.crop_capture_rect.h,
|
||||
};
|
||||
|
||||
gst_v4l2_object_set_crop (self->v4l2capture, &rect);
|
||||
self->selection_targets.crop_capture_need_config = FALSE;
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Configure crop for capture. left/top/width/height: %d %d %u %u",
|
||||
rect.left, rect.top, rect.width, rect.height);
|
||||
}
|
||||
|
||||
if (self->selection_targets.crop_output_need_config == TRUE) {
|
||||
struct v4l2_rect rect = {
|
||||
.left = self->selection_targets.crop_output_rect.x,
|
||||
.top = self->selection_targets.crop_output_rect.y,
|
||||
.width = self->selection_targets.crop_output_rect.w,
|
||||
.height = self->selection_targets.crop_output_rect.h,
|
||||
};
|
||||
|
||||
gst_v4l2_object_set_crop (self->v4l2output, &rect);
|
||||
self->selection_targets.crop_output_need_config = FALSE;
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Configure crop for output. left/top/width/height: %d %d %u %u",
|
||||
rect.left, rect.top, rect.width, rect.height);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_transform_selection_targets_config (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
const GstStructure *s = gst_value_get_structure (value);
|
||||
GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
|
||||
|
||||
if (s != NULL) {
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
if (s &&
|
||||
gst_structure_has_field (s, "compose-capture-x") &&
|
||||
gst_structure_has_field (s, "compose-capture-y") &&
|
||||
gst_structure_has_field (s, "compose-capture-w") &&
|
||||
gst_structure_has_field (s, "compose-capture-h")) {
|
||||
|
||||
gst_structure_get_int (s, "compose-capture-x",
|
||||
&(self->selection_targets.compose_capture_rect.x));
|
||||
gst_structure_get_int (s, "compose-capture-y",
|
||||
&(self->selection_targets.compose_capture_rect.y));
|
||||
gst_structure_get_int (s, "compose-capture-w",
|
||||
&(self->selection_targets.compose_capture_rect.w));
|
||||
gst_structure_get_int (s, "compose-capture-h",
|
||||
&(self->selection_targets.compose_capture_rect.h));
|
||||
|
||||
self->selection_targets.compose_capture_need_config = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"The compose configure for capture x,y,w,h : %d,%d,%d,%d",
|
||||
self->selection_targets.compose_capture_rect.x,
|
||||
self->selection_targets.compose_capture_rect.y,
|
||||
self->selection_targets.compose_capture_rect.w,
|
||||
self->selection_targets.compose_capture_rect.h);
|
||||
}
|
||||
|
||||
if (s &&
|
||||
gst_structure_has_field (s, "crop-capture-x") &&
|
||||
gst_structure_has_field (s, "crop-capture-y") &&
|
||||
gst_structure_has_field (s, "crop-capture-w") &&
|
||||
gst_structure_has_field (s, "crop-capture-h")) {
|
||||
|
||||
gst_structure_get_int (s, "crop-capture-x",
|
||||
&(self->selection_targets.crop_capture_rect.x));
|
||||
gst_structure_get_int (s, "crop-capture-y",
|
||||
&(self->selection_targets.crop_capture_rect.y));
|
||||
gst_structure_get_int (s, "crop-capture-w",
|
||||
&(self->selection_targets.crop_capture_rect.w));
|
||||
gst_structure_get_int (s, "crop-capture-h",
|
||||
&(self->selection_targets.crop_capture_rect.h));
|
||||
|
||||
self->selection_targets.crop_capture_need_config = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"The crop configure for capture x,y,w,h : %d,%d,%d,%d",
|
||||
self->selection_targets.crop_capture_rect.x,
|
||||
self->selection_targets.crop_capture_rect.y,
|
||||
self->selection_targets.crop_capture_rect.w,
|
||||
self->selection_targets.crop_capture_rect.h);
|
||||
}
|
||||
|
||||
if (s &&
|
||||
gst_structure_has_field (s, "crop-output-x") &&
|
||||
gst_structure_has_field (s, "crop-output-y") &&
|
||||
gst_structure_has_field (s, "crop-output-w") &&
|
||||
gst_structure_has_field (s, "crop-output-h")) {
|
||||
|
||||
gst_structure_get_int (s, "crop-output-x",
|
||||
&(self->selection_targets.crop_output_rect.x));
|
||||
gst_structure_get_int (s, "crop-output-y",
|
||||
&(self->selection_targets.crop_output_rect.y));
|
||||
gst_structure_get_int (s, "crop-output-w",
|
||||
&(self->selection_targets.crop_output_rect.w));
|
||||
gst_structure_get_int (s, "crop-output-h",
|
||||
&(self->selection_targets.crop_output_rect.h));
|
||||
|
||||
self->selection_targets.crop_output_need_config = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"The crop configure for output x,y,w,h : %d,%d,%d,%d",
|
||||
self->selection_targets.crop_output_rect.x,
|
||||
self->selection_targets.crop_output_rect.y,
|
||||
self->selection_targets.crop_output_rect.w,
|
||||
self->selection_targets.crop_output_rect.h);
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_transform_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
|
@ -76,6 +221,10 @@ gst_v4l2_transform_set_property (GObject * object,
|
|||
case PROP_DISABLE_PASSTHROUGH:
|
||||
self->disable_passthrough = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_SELECTION_TARGETS:
|
||||
gst_v4l2_transform_selection_targets_config (object, prop_id, value,
|
||||
pspec);
|
||||
break;
|
||||
|
||||
/* By default, only set on output */
|
||||
default:
|
||||
|
@ -930,6 +1079,8 @@ gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans,
|
|||
goto activate_failed;
|
||||
}
|
||||
|
||||
gst_v4l2_transform_selection_targets_apply (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Queue input buffer");
|
||||
ret =
|
||||
gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf, NULL);
|
||||
|
@ -1172,6 +1323,40 @@ gst_v4l2_transform_class_init (GstV4l2TransformClass * klass)
|
|||
g_param_spec_boolean ("disable-passthrough", "Disable Passthrough",
|
||||
"Forces passing buffers through the converter", FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstV4l2Transform:selection-targets:
|
||||
* According to v4l2 spec, we can do cropping or composing on capture/output
|
||||
* https://docs.kernel.org/6.1/userspace-api/media/v4l/selection-api.html
|
||||
*
|
||||
* so, here we export a property named selection-targets, and this property is boxed type
|
||||
* here is a example to set compose for capture
|
||||
* v4l2convert selection-targets="cid,compose-capture-x=100, compose-capture-y=100
|
||||
* compose-capture-w=300,compose-capture-h=200"
|
||||
*
|
||||
* contains following sub-properties:
|
||||
* 1) properties to set compose for capture
|
||||
* compose-capture-x
|
||||
* compose-capture-y
|
||||
* compose-capture-w
|
||||
* compose-capture-h
|
||||
*
|
||||
* 2) properties to set crop for capture
|
||||
* crop-capture-x
|
||||
* crop-capture-y
|
||||
* crop-capture-w
|
||||
* crop-capture-h
|
||||
*
|
||||
* 3)properties to set crop for output
|
||||
* crop-output-x
|
||||
* crop-output-y
|
||||
* crop-output-w
|
||||
* crop-output-h
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_SELECTION_TARGETS,
|
||||
g_param_spec_boxed ("selection-targets", "Selection Targets",
|
||||
"Configure compose/crop of convertor",
|
||||
GST_TYPE_STRUCTURE, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -46,6 +46,19 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstV4l2Transform GstV4l2Transform;
|
||||
typedef struct _GstV4l2TransformClass GstV4l2TransformClass;
|
||||
|
||||
typedef struct _GstSelectionTargets GstSelectionTargets ;
|
||||
struct _GstSelectionTargets
|
||||
{
|
||||
GstVideoRectangle compose_capture_rect;
|
||||
gboolean compose_capture_need_config;
|
||||
|
||||
GstVideoRectangle crop_capture_rect;
|
||||
gboolean crop_capture_need_config;
|
||||
|
||||
GstVideoRectangle crop_output_rect;
|
||||
gboolean crop_output_need_config;
|
||||
};
|
||||
|
||||
struct _GstV4l2Transform
|
||||
{
|
||||
GstBaseTransform parent;
|
||||
|
@ -63,6 +76,8 @@ struct _GstV4l2Transform
|
|||
GstCaps *outcaps;
|
||||
|
||||
gboolean disable_passthrough;
|
||||
|
||||
GstSelectionTargets selection_targets;
|
||||
};
|
||||
|
||||
struct _GstV4l2TransformClass
|
||||
|
|
Loading…
Reference in a new issue