From 1d45fbc56b37de006c9e82ef3142110cc29d6be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qian=20Hu=20=28=E8=83=A1=E9=AA=9E=29?= Date: Fri, 19 Jul 2024 19:44:57 +0800 Subject: [PATCH] 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: --- .../gst-plugins-good/sys/v4l2/gstv4l2object.c | 164 +++++++++++++----- 1 file changed, 120 insertions(+), 44 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c index f59ba1f285..6fc027d87d 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c @@ -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: * @obj: the object @@ -4689,20 +4744,24 @@ gboolean gst_v4l2_object_setup_padding (GstV4l2Object * obj) { GstVideoAlignment *align = &obj->align; - struct v4l2_rect crop; + struct v4l2_rect rect; if (align->padding_left + align->padding_top + 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; } - crop.left = align->padding_left; - crop.top = align->padding_top; - crop.width = obj->info.width; - crop.height = GST_VIDEO_INFO_FIELD_HEIGHT (&obj->info); + rect.left = align->padding_left; + rect.top = align->padding_top; + rect.width = obj->info.width; + 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 @@ -5152,6 +5211,18 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, 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) { GST_WARNING_OBJECT (obj->dbg_obj, "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; } + 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, &obj->align); @@ -5195,36 +5278,20 @@ gst_v4l2_object_match_buffer_layout (GstV4l2Object * obj, guint n_planes, } } - if (obj->align.padding_bottom) { - /* Crop because of vertical padding */ - GST_DEBUG_OBJECT (obj->dbg_obj, "crop because of bottom padding of %d", - obj->align.padding_bottom); + if (obj->align.padding_right || obj->align.padding_bottom) { + /* Setup padding */ + GST_DEBUG_OBJECT (obj->dbg_obj, + "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); } 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 gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj, const GstStructure * s, GstCaps * caps, guint buffer_size) @@ -5233,20 +5300,13 @@ gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj, GstVideoAlignment align; 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_structure_get_uint (s, "padding-top", &align.padding_top); - gst_structure_get_uint (s, "padding-bottom", &align.padding_bottom); - gst_structure_get_uint (s, "padding-left", &align.padding_left); - gst_structure_get_uint (s, "padding-right", &align.padding_right); + if (!gst_structure_has_name (s, "video-meta") || + !gst_buffer_pool_config_get_video_alignment (s, &align)) { + GST_WARNING_OBJECT (obj->dbg_obj, "Invalid params"); + return FALSE; + } if (align.padding_top || align.padding_bottom || align.padding_left || align.padding_right) { @@ -5256,6 +5316,11 @@ gst_v4l2_object_match_buffer_layout_from_struct (GstV4l2Object * obj, 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)) { GST_WARNING_OBJECT (obj->dbg_obj, "Failed to align video info"); return FALSE; @@ -5582,6 +5647,7 @@ gst_v4l2_object_propose_allocation (GstV4l2Object * obj, GstQuery * query) guint size, min, max; GstCaps *caps; gboolean need_pool; + GstStructure *allocation_meta = NULL; /* Set defaults allocation parameters */ 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); + 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 */ - 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) gst_object_unref (pool);