v4l2src: Consider framerate during caps selection

This simplifies the way it picks the closest caps to preference and take into
consideration the framerate to avoid picking high resolution at 5fps or so.
Simply calculate a "distance" of caps A and B from the preference and put
closest first, sorting by framerate first.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5956>
This commit is contained in:
Xavier Claessens 2023-12-06 20:42:32 -08:00 committed by Tim-Philipp Müller
parent 533b28cd6a
commit 0ce3a2782c

View file

@ -438,68 +438,41 @@ gst_v4l2_src_parse_fixed_struct (GstStructure * s,
gst_structure_get_fraction (s, "framerate", fps_n, fps_d);
}
/* TODO Consider framerate */
static gint
gst_v4l2src_fixed_caps_compare (GstCaps * caps_a, GstCaps * caps_b,
struct PreferredCapsInfo *pref)
{
GstStructure *a, *b;
gint aw = G_MAXINT, ah = G_MAXINT, ad = G_MAXINT;
gint bw = G_MAXINT, bh = G_MAXINT, bd = G_MAXINT;
gint ret;
gint aw = G_MAXINT, ah = G_MAXINT;
gint bw = G_MAXINT, bh = G_MAXINT;
gint a_fps_n = G_MAXINT, a_fps_d = 1;
gint b_fps_n = G_MAXINT, b_fps_d = 1;
gint a_distance, b_distance;
a = gst_caps_get_structure (caps_a, 0);
b = gst_caps_get_structure (caps_b, 0);
gst_v4l2_src_parse_fixed_struct (a, &aw, &ah, NULL, NULL);
gst_v4l2_src_parse_fixed_struct (b, &bw, &bh, NULL, NULL);
gst_v4l2_src_parse_fixed_struct (a, &aw, &ah, &a_fps_n, &a_fps_d);
gst_v4l2_src_parse_fixed_struct (b, &bw, &bh, &b_fps_n, &b_fps_d);
/* When both are smaller then pref, just append to the end */
if ((bw < pref->width || bh < pref->height)
&& (aw < pref->width || ah < pref->height)) {
ret = 1;
goto done;
}
// Sort first the one with closest framerate to preference. Note that any
// framerate lower then 1 frame per second will be considered the same. In
// practice this should be fine considering that these framerate only exists
// for still picture, in which case the resolution is most likely the key.
a_distance = ABS ((a_fps_n / a_fps_d) - (pref->fps_n / pref->fps_d));
b_distance = ABS ((b_fps_n / b_fps_d) - (pref->fps_n / pref->fps_d));
if (a_distance != b_distance)
return a_distance - b_distance;
/* If a is smaller then pref and not b, then a goes after b */
if (aw < pref->width || ah < pref->height) {
ret = 1;
goto done;
}
// If same framerate, sort first the one with closest resolution to preference
a_distance = ABS (aw * ah - pref->width * pref->height);
b_distance = ABS (bw * bh - pref->width * pref->height);
/* If b is smaller then pref and not a, then a goes before b */
if (bw < pref->width || bh < pref->height) {
ret = -1;
goto done;
}
gint ret = a_distance - b_distance;
/* Both are larger or equal to the preference, prefer the smallest */
ad = MAX (1, aw - pref->width) * MAX (1, ah - pref->height);
bd = MAX (1, bw - pref->width) * MAX (1, bh - pref->height);
GST_TRACE ("Placing %" GST_PTR_FORMAT " %s %" GST_PTR_FORMAT,
caps_a, ret > 0 ? "after" : "before", caps_b);
/* Adjust slightly in case width/height matched the preference */
if (aw == pref->width)
ad -= 1;
if (ah == pref->height)
ad -= 1;
if (bw == pref->width)
bd -= 1;
if (bh == pref->height)
bd -= 1;
/* If the choices are equivalent, maintain the order */
if (ad == bd)
ret = 1;
else
ret = ad - bd;
done:
GST_TRACE ("Placing %ix%i (%s) %s %ix%i (%s)", aw, ah,
gst_structure_get_string (a, "format"), ret > 0 ? "after" : "before", bw,
bh, gst_structure_get_string (b, "format"));
return ret;
}