diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c index 7f7b3f98df..4188f58b72 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c @@ -356,6 +356,79 @@ gst_v4l2_decoder_set_sink_fmt (GstV4l2Decoder * self, guint32 pix_fmt, return TRUE; } +static GstCaps * +gst_v4l2_decoder_enum_size_for_format (GstV4l2Decoder * self, + guint32 pixelformat, gint index, gint unscaled_width, gint unscaled_height) +{ + struct v4l2_frmsizeenum size; + GstVideoFormat format; + gint ret; + gboolean res; + + memset (&size, 0, sizeof (struct v4l2_frmsizeenum)); + size.index = index; + size.pixel_format = pixelformat; + + GST_DEBUG_OBJECT (self, "enumerate size index %d for %" GST_FOURCC_FORMAT, + index, GST_FOURCC_ARGS (pixelformat)); + + ret = ioctl (self->video_fd, VIDIOC_ENUM_FRAMESIZES, &size); + + if (ret < 0) + return NULL; + + if (size.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + GST_WARNING_OBJECT (self, "V4L2_FRMSIZE type not supported"); + return NULL; + } + + if (gst_util_fraction_compare (unscaled_width, unscaled_height, + size.discrete.width, size.discrete.height)) { + GST_DEBUG_OBJECT (self, + "Pixel ratio modification not supported %dx%d %dx%d (%d)", + unscaled_width, unscaled_height, size.discrete.width, + size.discrete.height, ret); + return NULL; + } + + res = gst_v4l2_format_to_video_format (pixelformat, &format); + g_assert (res); + + GST_DEBUG_OBJECT (self, "get size (%d x %d) index %d for %" GST_FOURCC_FORMAT, + size.discrete.width, size.discrete.height, index, + GST_FOURCC_ARGS (pixelformat)); + + return gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, + gst_video_format_to_string (format), + "width", G_TYPE_INT, size.discrete.width, + "height", G_TYPE_INT, size.discrete.height, NULL); +} + +static GstCaps * +gst_v4l2_decoder_probe_caps_for_format (GstV4l2Decoder * self, + guint32 pixelformat, gint unscaled_width, gint unscaled_height) +{ + gint index = 0; + GstCaps *caps, *tmp; + GstVideoFormat format; + + GST_DEBUG_OBJECT (self, "enumerate size for %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (pixelformat)); + + if (!gst_v4l2_format_to_video_format (pixelformat, &format)) + return gst_caps_new_empty (); + + caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, + gst_video_format_to_string (format), NULL); + + while ((tmp = gst_v4l2_decoder_enum_size_for_format (self, pixelformat, + index++, unscaled_width, unscaled_height))) { + caps = gst_caps_merge (caps, tmp); + } + + return caps; +} + GstCaps * gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self) { @@ -363,10 +436,7 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self) struct v4l2_format fmt = { .type = self->src_buf_type, }; - GstVideoFormat format; GstCaps *caps; - GValue list = G_VALUE_INIT; - GValue value = G_VALUE_INIT; gint i; g_return_val_if_fail (self->opened, FALSE); @@ -377,20 +447,15 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self) return FALSE; } - /* We first place a structure with the default pixel format */ - if (gst_v4l2_format_to_video_format (fmt.fmt.pix_mp.pixelformat, &format)) - caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, - gst_video_format_to_string (format), NULL); - else - caps = gst_caps_new_empty (); + caps = + gst_v4l2_decoder_probe_caps_for_format (self, + fmt.fmt.pix_mp.pixelformat, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height); /* And then enumerate other possible formats and place that as a second * structure in the caps */ - g_value_init (&list, GST_TYPE_LIST); - g_value_init (&value, G_TYPE_STRING); - for (i = 0; ret >= 0; i++) { struct v4l2_fmtdesc fmtdesc = { i, self->src_buf_type, }; + GstCaps *tmp; ret = ioctl (self->video_fd, VIDIOC_ENUM_FMT, &fmtdesc); if (ret < 0) { @@ -400,19 +465,9 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self) continue; } - if (gst_v4l2_format_to_video_format (fmtdesc.pixelformat, &format)) { - g_value_set_static_string (&value, gst_video_format_to_string (format)); - gst_value_list_append_value (&list, &value); - } - } - g_value_reset (&value); - - if (gst_value_list_get_size (&list) > 0) { - GstStructure *str = gst_structure_new_empty ("video/x-raw"); - gst_structure_take_value (str, "format", &list); - gst_caps_append_structure (caps, str); - } else { - g_value_reset (&list); + tmp = gst_v4l2_decoder_probe_caps_for_format (self, fmtdesc.pixelformat, + fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height); + caps = gst_caps_merge (caps, tmp); } return caps;