From b80f4a1fa4ff86bd44fafe187c2865e9eedfd5db Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 6 Dec 2023 20:42:32 -0800 Subject: [PATCH] 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: --- .../gst-plugins-good/sys/v4l2/gstv4l2src.c | 69 ++++++------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c index 07f8718794..68d8f7f873 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2src.c @@ -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; }