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