89 lines
3.4 KiB
Diff
89 lines
3.4 KiB
Diff
# UNDF: UNDF-2026-000000094
|
||
--- a/gst/gstelementfactory.c
|
||
+++ b/gst/gstelementfactory.c
|
||
@@ -1183,6 +1183,73 @@ gst_element_factory_list_filter (GList * list,
|
||
const GstCaps * caps, GstPadDirection direction, gboolean subsetonly)
|
||
{
|
||
GQueue results = G_QUEUE_INIT;
|
||
+ GHashTable *caps_index;
|
||
+ GList *indexed_candidates;
|
||
+
|
||
+ /*
|
||
+ * CWE-407 fix: build a temporary media-type → factory hash for this filter
|
||
+ * call. The outer list (already pre-filtered by type via list_get_elements)
|
||
+ * is typically 50–500 entries. Without indexing, every entry requires
|
||
+ * gst_caps_can_intersect() which itself is O(S1 × S2).
|
||
+ *
|
||
+ * Strategy: extract the media type (first structure name) from each factory's
|
||
+ * pad templates during a single O(N) pass to build a hash. Then look up only
|
||
+ * the query caps media type. Factories with ANY/empty caps are kept in a
|
||
+ * fallback list examined after the hash hits.
|
||
+ *
|
||
+ * This reduces the inner loop from O(N × M × S²) to O(k × M × S²) where
|
||
+ * k is the number of factories that handle the specific media type (≈1–5).
|
||
+ */
|
||
+
|
||
+ if (!list || !caps || GST_CAPS_IS_ANY (caps) || GST_CAPS_IS_EMPTY (caps))
|
||
+ goto slow_path;
|
||
+
|
||
+ caps_index = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
|
||
+ (GDestroyNotify) g_list_free);
|
||
+
|
||
+ {
|
||
+ GList *fallback = NULL;
|
||
+ for (GList *l = list; l; l = l->next) {
|
||
+ GstElementFactory *factory = (GstElementFactory *) l->data;
|
||
+ const GList *templates =
|
||
+ gst_element_factory_get_static_pad_templates (factory);
|
||
+ gboolean has_any = FALSE;
|
||
+ for (const GList *t = templates; t; t = g_list_next (t)) {
|
||
+ GstStaticPadTemplate *tmpl = t->data;
|
||
+ if (tmpl->direction != direction) continue;
|
||
+ const gchar *tmpl_str = tmpl->static_caps.string;
|
||
+ if (!tmpl_str || g_str_has_prefix (tmpl_str, "ANY") ||
|
||
+ g_str_has_prefix (tmpl_str, "EMPTY")) {
|
||
+ has_any = TRUE;
|
||
+ continue;
|
||
+ }
|
||
+ /* Extract media type: everything up to first ',' or ' ' */
|
||
+ const gchar *comma = strpbrk (tmpl_str, ", ");
|
||
+ gchar *mtype = comma
|
||
+ ? g_strndup (tmpl_str, (gsize)(comma - tmpl_str))
|
||
+ : g_strdup (tmpl_str);
|
||
+ GList *bucket = g_hash_table_lookup (caps_index, mtype);
|
||
+ g_hash_table_insert (caps_index, mtype,
|
||
+ g_list_prepend (bucket, factory));
|
||
+ }
|
||
+ if (has_any)
|
||
+ fallback = g_list_prepend (fallback, factory);
|
||
+ }
|
||
+ /* Merge hash hits + fallback into candidate list */
|
||
+ indexed_candidates = g_list_copy (fallback);
|
||
+ g_list_free (fallback);
|
||
+ for (guint i = 0; i < gst_caps_get_size (caps); i++) {
|
||
+ GstStructure *s = gst_caps_get_structure (caps, i);
|
||
+ const gchar *mtype = gst_structure_get_name (s);
|
||
+ GList *bucket = g_hash_table_lookup (caps_index, mtype);
|
||
+ for (GList *b = bucket; b; b = b->next)
|
||
+ if (!g_list_find (indexed_candidates, b->data))
|
||
+ indexed_candidates = g_list_prepend (indexed_candidates, b->data);
|
||
+ }
|
||
+ g_hash_table_destroy (caps_index);
|
||
+ /* Run the actual caps check only on the candidate set */
|
||
+ list = indexed_candidates;
|
||
+ }
|
||
+
|
||
+slow_path:
|
||
GST_DEBUG ("finding factories");
|
||
|
||
/* loop over all the factories */
|
||
@@ -1224,6 +1291,12 @@ gst_element_factory_list_filter (GList * list,
|
||
}
|
||
}
|
||
}
|
||
+
|
||
+ if (list == indexed_candidates)
|
||
+ g_list_free (indexed_candidates);
|
||
+
|
||
return results.head;
|
||
}
|