mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-21 17:21:13 +00:00
v4l2object: pass buffer align info for upstream
if downstream v4l2 output has large alignment requirement this patch will pass align info for upstream element and decide allocation will use these info to meet alignment requirement. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7201>
This commit is contained in:
parent
53007b5d83
commit
1d45fbc56b
1 changed files with 120 additions and 44 deletions
|
@ -4606,6 +4606,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.
|
||||||
|
*/
|
||||||
|
static 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:
|
* gst_v4l2_object_set_crop:
|
||||||
* @obj: the object
|
* @obj: the object
|
||||||
|
@ -4689,20 +4744,24 @@ gboolean
|
||||||
gst_v4l2_object_setup_padding (GstV4l2Object * obj)
|
gst_v4l2_object_setup_padding (GstV4l2Object * obj)
|
||||||
{
|
{
|
||||||
GstVideoAlignment *align = &obj->align;
|
GstVideoAlignment *align = &obj->align;
|
||||||
struct v4l2_rect crop;
|
struct v4l2_rect rect;
|
||||||
|
|
||||||
if (align->padding_left + align->padding_top
|
if (align->padding_left + align->padding_top
|
||||||
+ align->padding_right + align->padding_bottom == 0) {
|
+ align->padding_right + align->padding_bottom == 0) {
|
||||||
GST_DEBUG_OBJECT (obj->dbg_obj, "no cropping needed");
|
GST_DEBUG_OBJECT (obj->dbg_obj, "no cropping/composing needed");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
crop.left = align->padding_left;
|
rect.left = align->padding_left;
|
||||||
crop.top = align->padding_top;
|
rect.top = align->padding_top;
|
||||||
crop.width = obj->info.width;
|
rect.width = obj->info.width;
|
||||||
crop.height = GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info);
|
rect.height = GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info);
|
||||||
|
|
||||||
return gst_v4l2_object_set_crop (obj, &crop);
|
if (V4L2_TYPE_IS_OUTPUT (obj->type)) {
|
||||||
|
return gst_v4l2_object_set_crop (obj, &rect);
|
||||||
|
} else {
|
||||||
|
return gst_v4l2_object_set_compose (obj, &rect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -5152,6 +5211,18 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes,
|
||||||
wanted_stride[0] = plane_stride;
|
wanted_stride[0] = plane_stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, "Wanted format of %dx%d",
|
||||||
|
format.fmt.pix_mp.width, format.fmt.pix_mp.height);
|
||||||
|
if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
|
||||||
|
for (guint i = 0; i < format.fmt.pix_mp.num_planes; i++)
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, " [%u] stride %d, sizeimage %d", i,
|
||||||
|
format.fmt.pix_mp.plane_fmt[i].bytesperline,
|
||||||
|
format.fmt.pix_mp.plane_fmt[i].sizeimage);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, " stride %d, sizeimage %d",
|
||||||
|
format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
|
||||||
|
}
|
||||||
|
|
||||||
if (obj->ioctl (obj->video_fd, VIDIOC_S_FMT, &format) < 0) {
|
if (obj->ioctl (obj->video_fd, VIDIOC_S_FMT, &format) < 0) {
|
||||||
GST_WARNING_OBJECT (obj->dbg_obj,
|
GST_WARNING_OBJECT (obj->dbg_obj,
|
||||||
"Something went wrong trying to update current format: %s",
|
"Something went wrong trying to update current format: %s",
|
||||||
|
@ -5159,6 +5230,18 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, "Got format of %dx%d",
|
||||||
|
format.fmt.pix_mp.width, format.fmt.pix_mp.height);
|
||||||
|
if (V4L2_TYPE_IS_MULTIPLANAR (obj->type)) {
|
||||||
|
for (guint i = 0; i < format.fmt.pix_mp.num_planes; i++)
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, " [%u] stride %d, sizeimage %d", i,
|
||||||
|
format.fmt.pix_mp.plane_fmt[i].bytesperline,
|
||||||
|
format.fmt.pix_mp.plane_fmt[i].sizeimage);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (obj->dbg_obj, " stride %d, sizeimage %d",
|
||||||
|
format.fmt.pix.bytesperline, format.fmt.pix.sizeimage);
|
||||||
|
}
|
||||||
|
|
||||||
gst_v4l2_object_save_format (obj, obj->fmtdesc, &format, &obj->info,
|
gst_v4l2_object_save_format (obj, obj->fmtdesc, &format, &obj->info,
|
||||||
&obj->align);
|
&obj->align);
|
||||||
|
|
||||||
|
@ -5195,36 +5278,20 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->align.padding_bottom) {
|
if (obj->align.padding_right || obj->align.padding_bottom) {
|
||||||
/* Crop because of vertical padding */
|
/* Setup padding */
|
||||||
GST_DEBUG_OBJECT (obj->dbg_obj, "crop because of bottom padding of %d",
|
GST_DEBUG_OBJECT (obj->dbg_obj,
|
||||||
obj->align.padding_bottom);
|
"setup padding (top: %u left: %u right: %u bottom: %u)",
|
||||||
|
obj->align.padding_top,
|
||||||
|
obj->align.padding_left,
|
||||||
|
obj->align.padding_right, obj->align.padding_bottom);
|
||||||
|
|
||||||
gst_v4l2_object_setup_padding (obj);
|
gst_v4l2_object_setup_padding (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
validate_video_meta_struct (GstV4l2Object * obj, const GstStructure * s)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; i < gst_structure_n_fields (s); i++) {
|
|
||||||
const gchar *name = gst_structure_nth_field_name (s, i);
|
|
||||||
|
|
||||||
if (!g_str_equal (name, "padding-top")
|
|
||||||
&& !g_str_equal (name, "padding-bottom")
|
|
||||||
&& !g_str_equal (name, "padding-left")
|
|
||||||
&& !g_str_equal (name, "padding-right")) {
|
|
||||||
GST_WARNING_OBJECT (obj->dbg_obj, "Unknown video meta field: '%s'", name);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj,
|
gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj,
|
||||||
const GstStructure * s, GstCaps * caps, guint buffer_size)
|
const GstStructure * s, GstCaps * caps, guint buffer_size)
|
||||||
|
@ -5233,20 +5300,13 @@ gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj,
|
||||||
GstVideoAlignment align;
|
GstVideoAlignment align;
|
||||||
gsize plane_size[GST_VIDEO_MAX_PLANES];
|
gsize plane_size[GST_VIDEO_MAX_PLANES];
|
||||||
|
|
||||||
if (!validate_video_meta_struct (obj, s))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!gst_video_info_from_caps (&info, caps)) {
|
|
||||||
GST_WARNING_OBJECT (obj->dbg_obj, "Failed to create video info");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_video_alignment_reset (&align);
|
gst_video_alignment_reset (&align);
|
||||||
|
|
||||||
gst_structure_get_uint (s, "padding-top", &align.padding_top);
|
if (!gst_structure_has_name (s, "video-meta") ||
|
||||||
gst_structure_get_uint (s, "padding-bottom", &align.padding_bottom);
|
!gst_buffer_pool_config_get_video_alignment (s, &align)) {
|
||||||
gst_structure_get_uint (s, "padding-left", &align.padding_left);
|
GST_WARNING_OBJECT (obj->dbg_obj, "Invalid params");
|
||||||
gst_structure_get_uint (s, "padding-right", &align.padding_right);
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (align.padding_top || align.padding_bottom || align.padding_left ||
|
if (align.padding_top || align.padding_bottom || align.padding_left ||
|
||||||
align.padding_right) {
|
align.padding_right) {
|
||||||
|
@ -5256,6 +5316,11 @@ gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj,
|
||||||
align.padding_right);
|
align.padding_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!gst_video_info_from_caps (&info, caps)) {
|
||||||
|
GST_WARNING_OBJECT (obj->dbg_obj, "Failed to create video info");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_video_info_align_full (&info, &align, plane_size)) {
|
if (!gst_video_info_align_full (&info, &align, plane_size)) {
|
||||||
GST_WARNING_OBJECT (obj->dbg_obj, "Failed to align video info");
|
GST_WARNING_OBJECT (obj->dbg_obj, "Failed to align video info");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -5582,6 +5647,7 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query)
|
||||||
guint size, min, max;
|
guint size, min, max;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
gboolean need_pool;
|
gboolean need_pool;
|
||||||
|
GstStructure *allocation_meta = NULL;
|
||||||
|
|
||||||
/* Set defaults allocation parameters */
|
/* Set defaults allocation parameters */
|
||||||
size = obj->info.size;
|
size = obj->info.size;
|
||||||
|
@ -5633,8 +5699,18 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query)
|
||||||
|
|
||||||
gst_query_add_allocation_pool (query, pool, size, min, max);
|
gst_query_add_allocation_pool (query, pool, size, min, max);
|
||||||
|
|
||||||
|
if (obj->align.padding_top || obj->align.padding_bottom ||
|
||||||
|
obj->align.padding_left || obj->align.padding_right) {
|
||||||
|
allocation_meta = gst_structure_new_empty ("video-meta");
|
||||||
|
gst_buffer_pool_config_set_video_alignment (allocation_meta, &obj->align);
|
||||||
|
}
|
||||||
|
|
||||||
/* we also support various metadata */
|
/* we also support various metadata */
|
||||||
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
|
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE,
|
||||||
|
allocation_meta);
|
||||||
|
|
||||||
|
if (allocation_meta)
|
||||||
|
gst_structure_free (allocation_meta);
|
||||||
|
|
||||||
if (pool)
|
if (pool)
|
||||||
gst_object_unref (pool);
|
gst_object_unref (pool);
|
||||||
|
|
Loading…
Reference in a new issue