v4l2codecs: enumerate all possible formats

Some decoder may also allow to (down) scale the decoded video.
Use VIDIOC_ENUM_FRAMESIZES iotcl to enumerate the possible output
formats resolutions.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2589>
This commit is contained in:
Benjamin Gaignard 2021-06-22 14:43:29 +02:00 committed by GStreamer Marge Bot
parent 85fe9fb61d
commit d3a01eccae

View file

@ -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;