diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstautoconvert.c b/subprojects/gst-plugins-bad/gst/autoconvert/gstautoconvert.c index 89de94b693..bc6bab3e17 100644 --- a/subprojects/gst-plugins-bad/gst/autoconvert/gstautoconvert.c +++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstautoconvert.c @@ -43,6 +43,8 @@ #include "gstautoconvert.h" #include +GST_DEBUG_CATEGORY (autoconvert_debug); +#define GST_CAT_DEFAULT (autoconvert_debug) struct _GstAutoConvert { GstBaseAutoConvert parent; @@ -155,6 +157,9 @@ gst_auto_convert_class_init (GstAutoConvertClass * klass) GObjectClass *gobject_class = (GObjectClass *) klass; GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GST_DEBUG_CATEGORY_INIT (autoconvert_debug, "autoconvert", 0, + "Auto convert element"); + gobject_class->set_property = gst_auto_convert_set_property; gobject_class->get_property = gst_auto_convert_get_property; @@ -187,6 +192,8 @@ gst_auto_convert_class_init (GstAutoConvertClass * klass) "An element factory name", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_BASE_AUTO_CONVERT_CLASS (klass)->registers_filters = FALSE; } static void diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c index c722b83e0d..e91861cf3e 100644 --- a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c +++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c @@ -1,6 +1,8 @@ /* GStreamer * Copyright 2010 ST-Ericsson SA * @author: Benjamin Gaignard + * Copyright 2023 Igalia S.L. + * @author: Thibault Saunier * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -39,215 +41,20 @@ GST_DEBUG_CATEGORY (autovideoconvert_debug); struct _GstAutoVideoConvert { - GstAutoConvert parent; + GstBaseAutoConvert parent; }; G_DEFINE_TYPE (GstAutoVideoConvert, gst_auto_video_convert, - GST_TYPE_AUTO_CONVERT); + GST_TYPE_BASE_AUTO_CONVERT); GST_ELEMENT_REGISTER_DEFINE (autovideoconvert, "autovideoconvert", GST_RANK_NONE, gst_auto_video_convert_get_type ()); -static gboolean -gst_auto_video_convert_element_filter (GstPluginFeature * feature, - GstAutoVideoConvert * autovideoconvert) -{ - const gchar *klass; - - /* we only care about element factories */ - if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature))) - return FALSE; - - if (!g_strcmp0 (GST_OBJECT_NAME (feature), "autovideoconvert")) - return FALSE; - - if (gst_plugin_feature_get_rank (feature) <= GST_RANK_NONE) - return FALSE; - - klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY_CAST (feature), - GST_ELEMENT_METADATA_KLASS); - /* only select color space converter */ - if (strstr (klass, "Colorspace") && strstr (klass, "Scaler") && - strstr (klass, "Converter") && strstr (klass, "Video")) { - GST_DEBUG_OBJECT (autovideoconvert, - "gst_auto_video_convert_element_filter found %s", - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (feature))); - return TRUE; - } - return FALSE; -} - -typedef struct -{ - const gchar *name; - const gchar *bindesc; - GstRank rank; -} KnownBin; - -#define GST_AUTOCONVERT_WNBIN_QUARK g_quark_from_static_string("autovideoconvert-wn-bin-quark") -static void -gst_auto_convert_wn_bin_class_init (GstBinClass * class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (class); - KnownBin *b = g_type_get_qdata (G_OBJECT_CLASS_TYPE (class), - GST_AUTOCONVERT_WNBIN_QUARK); - gchar **factory_names = g_strsplit (b->bindesc, " ! ", -1); - gint nfactories = 0; - GstElementFactory *factory; - GstStaticPadTemplate *template = NULL; - - for (nfactories = 0; factory_names[nfactories + 1]; nfactories++); - - factory = gst_element_factory_find (factory_names[0]); - for (GList * tmp = - (GList *) gst_element_factory_get_static_pad_templates (factory); tmp; - tmp = tmp->next) { - if (((GstStaticPadTemplate *) tmp->data)->direction == GST_PAD_SINK) { - template = tmp->data; - break; - } - } - gst_element_class_add_static_pad_template (element_class, template); - - template = NULL; - factory = gst_element_factory_find (factory_names[nfactories]); - for (GList * tmp = - (GList *) gst_element_factory_get_static_pad_templates (factory); tmp; - tmp = tmp->next) { - if (((GstStaticPadTemplate *) tmp->data)->direction == GST_PAD_SRC) { - template = tmp->data; - break; - } - } - g_assert (template); - gst_element_class_add_static_pad_template (element_class, template); - - gst_element_class_set_metadata (element_class, b->name, - "Scaler/Colorspace/Converter/Video", b->name, - "Thibault Saunier "); - - g_strfreev (factory_names); -} - -static void -gst_auto_convert_wn_bin_init (GstBin * self) -{ - KnownBin *b = - g_type_get_qdata (G_OBJECT_TYPE (self), GST_AUTOCONVERT_WNBIN_QUARK); - GError *err = NULL; - GstElement *subbin = gst_parse_bin_from_description (b->bindesc, TRUE, &err); - - if (err) - g_error ("%s couldn't be built?!: %s", b->name, err->message); - - gst_bin_add (self, subbin); - gst_element_add_pad (GST_ELEMENT (self), gst_ghost_pad_new ("sink", - subbin->sinkpads->data)); - gst_element_add_pad (GST_ELEMENT (self), gst_ghost_pad_new ("src", - subbin->srcpads->data)); -} - -static void -register_well_known_bins (void) -{ - GTypeInfo typeinfo = { - sizeof (GstBinClass), - (GBaseInitFunc) NULL, - NULL, - (GClassInitFunc) gst_auto_convert_wn_bin_class_init, - NULL, - NULL, - sizeof (GstBin), - 0, - (GInstanceInitFunc) gst_auto_convert_wn_bin_init, - }; - /* *INDENT-OFF* */ - const KnownBin subbins[] = { - { - .name = "auto+bayer2rgbcolorconvert", - .bindesc = "bayer2rgb ! videoconvertscale ! videoflip method=automatic ! videoconvertscale", - .rank = GST_RANK_SECONDARY, - }, - { - .name = "auto+colorconvertrgb2bayer", - .bindesc = "videoconvertscale ! videoflip method=automatic ! videoconvertscale ! rgb2bayer", - .rank = GST_RANK_SECONDARY, - }, - { - /* Fallback to only videoconvertscale if videoflip is not available */ - .name = "auto+colorconvert-fallback", - .bindesc = "videoconvertscale", - .rank = GST_RANK_MARGINAL, - }, - { - .name = "auto+colorconvert", - .bindesc = "videoconvertscale ! videoflip method=automatic ! videoconvertscale", - .rank = GST_RANK_SECONDARY, - }, - { - .name = "auto+glcolorconvert", - .bindesc = "glcolorconvert ! glcolorscale ! glvideoflip method=automatic ! glcolorconvert", - .rank = GST_RANK_PRIMARY, - }, - }; - /* *INDENT-ON* */ - - for (gint i = 0; i < G_N_ELEMENTS (subbins); i++) { - GType type = 0; - KnownBin *b = NULL; - GstElement *subbin = gst_parse_launch (subbins[i].bindesc, NULL); - - if (!subbin) { - GST_INFO ("Ignoring possible Converting scaler: %s '%s'", subbins[i].name, - subbins[i].bindesc); - continue; - } - - gst_object_unref (subbin); - - type = g_type_register_static (GST_TYPE_BIN, subbins[i].name, &typeinfo, 0); - b = g_malloc0 (sizeof (KnownBin)); - b->name = g_strdup (subbins[i].name); - b->bindesc = g_strdup (subbins[i].bindesc); - b->rank = subbins[i].rank; - - g_type_set_qdata (type, GST_AUTOCONVERT_WNBIN_QUARK, b); - - if (!gst_element_register (NULL, b->name, b->rank, type)) { - g_warning ("Failed to register %s", "autoglcolorconverter"); - } - } -} - -static GList * -gst_auto_video_convert_create_factory_list (GstAutoConvert * autoconvert) -{ - GList *result = NULL; - static gpointer registered_well_known_bins = FALSE; - - if (g_once_init_enter (®istered_well_known_bins)) { - register_well_known_bins (); - g_once_init_leave (®istered_well_known_bins, (gpointer) TRUE); - } - - /* get the feature list using the filter */ - result = gst_registry_feature_filter (gst_registry_get (), - (GstPluginFeatureFilter) gst_auto_video_convert_element_filter, - FALSE, autoconvert); - - /* sort on rank and name */ - result = g_list_sort (result, gst_plugin_feature_rank_compare_func); - - return result; -} - static void gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass) { GstElementClass *gstelement_class = (GstElementClass *) klass; - ((GstAutoConvertClass *) klass)->load_factories = - gst_auto_video_convert_create_factory_list; GST_DEBUG_CATEGORY_INIT (autovideoconvert_debug, "autovideoconvert", 0, "Auto color space converter"); @@ -255,10 +62,123 @@ gst_auto_video_convert_class_init (GstAutoVideoConvertClass * klass) "Select color space converter and scalers based on caps", "Bin/Colorspace/Scale/Video/Converter", "Selects the right color space converter based on the caps", - "Benjamin Gaignard "); + "Thibault Saunier "); } static void gst_auto_video_convert_init (GstAutoVideoConvert * autovideoconvert) { + /* *INDENT-OFF* */ + static const GstAutoVideoFilterGenerator gen[] = { + { + .first_elements = { "bayer2rgb", NULL}, + .colorspace_converters = { "videoconvertscale", NULL }, + .last_elements = { NULL } , + .filters = { NULL}, + .rank = GST_RANK_SECONDARY, + }, + { + .first_elements = { NULL, }, + .colorspace_converters = { "videoconvertscale", NULL }, + .last_elements = { "rgb2bayer", NULL }, + .filters = { NULL }, + .rank = GST_RANK_SECONDARY, + }, + { + .first_elements = { NULL, }, + .colorspace_converters = { "videoconvertscale", NULL }, + .last_elements = { NULL, }, + .filters = { NULL }, + .rank = GST_RANK_SECONDARY, + }, + { + .first_elements = { NULL, }, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { NULL, }, + .filters = { NULL }, + .rank = GST_RANK_PRIMARY, + }, + { + .first_elements = { "glupload", }, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { NULL, }, + .filters = { NULL }, + .rank = GST_RANK_PRIMARY, + }, + { + .first_elements = { "videoconvertscale", "glupload", NULL }, + .colorspace_converters = { NULL }, + .last_elements = { NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL + 1, + }, + { + .first_elements = { "glcolorconvert", "gldownload", NULL }, + .colorspace_converters = { NULL }, + .last_elements = { NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL + 2, + }, + { /* Worst case we upload/download as required */ + .first_elements = { "glupload", "gldownload", NULL }, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { "glupload", "gldownload", NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL + 1, + }, + { /* Pure cuda is preferred */ + .first_elements = { NULL }, + .colorspace_converters = { "cudaconvertscale", NULL }, + .last_elements = { NULL }, + .filters = { NULL }, + .rank = GST_RANK_PRIMARY, + }, + { /* CUDA -> GL */ + .first_elements = { "capsfilter caps=video/x-raw(memory:CUDAMemory)", "cudadownload", NULL }, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { "glupload", "gldownload", NULL }, + .filters = { NULL }, + .rank = GST_RANK_SECONDARY, + }, + { /* GL memory to cuda */ + .first_elements = { NULL }, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { "cudaupload", "capsfilter caps=video/x-raw(memory:CUDAMemory)", NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL, + }, + { /* System memory to cuda */ + .first_elements = { NULL }, + .colorspace_converters = { "videoconvertscale", NULL }, + .last_elements = { "cudaupload", "capsfilter caps=video/x-raw(memory:CUDAMemory)", NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL, + }, + { + .first_elements = { NULL, }, + .colorspace_converters = { "d3d11convert", NULL }, + .last_elements = { NULL, }, + .filters = { NULL }, + .rank = GST_RANK_PRIMARY, + }, + { + .first_elements = { "d3d11download", "d3d11upload", NULL}, + .colorspace_converters = { "glcolorconvert", "glcolorscale", "glcolorconvert", NULL }, + .last_elements = { "d3d11download", "d3d11upload", NULL }, + .filters = { NULL }, + .rank = GST_RANK_MARGINAL, + }, + { /* Worst case we upload/download as required */ + .first_elements = { NULL}, + .colorspace_converters = { NULL }, + .last_elements = { NULL }, + .filters = { NULL }, + .rank = 0, + }, + }; + /* *INDENT-ON* */ + + + gst_auto_video_register_well_known_bins (GST_BASE_AUTO_CONVERT + (autovideoconvert), gen); } diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.h b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.h index a0ecb9b650..5920094b46 100644 --- a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.h +++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.h @@ -1,6 +1,8 @@ /* GStreamer * Copyright 2010 ST-Ericsson SA * @author: Benjamin Gaignard + * Copyright 2023 Igalia S.L. + * @author: Thibault Saunier * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,8 +29,20 @@ G_BEGIN_DECLS -G_DECLARE_FINAL_TYPE(GstAutoVideoConvert, gst_auto_video_convert, GST, AUTO_VIDEO_CONVERT, GstAutoConvert); +G_DECLARE_FINAL_TYPE(GstAutoVideoConvert, gst_auto_video_convert, GST, AUTO_VIDEO_CONVERT, GstBaseAutoConvert); GST_ELEMENT_REGISTER_DECLARE (autovideoconvert); +typedef struct +{ + const gchar *first_elements[4]; + const gchar *colorspace_converters[4]; + const gchar *last_elements[4]; + + const gchar *possible_filters[4]; + GstRank rank; +} GstAutoVideoConvertFilterBinsGenerator; + +void gst_auto_video_register_well_known_bins (GstAutoVideoConvert *self, GstAutoVideoConvertFilterBinsGenerator *gen); + G_END_DECLS #endif /* __GST_AUTO_VIDEO_CONVERT_H__ */ diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.c b/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.c index 90859c8271..33b681738e 100644 --- a/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.c +++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.c @@ -102,8 +102,8 @@ static gboolean gst_base_auto_convert_internal_src_event (GstPad * pad, GstObject * parent, GstEvent * event); static gboolean gst_base_auto_convert_internal_src_query (GstPad * pad, GstObject * parent, GstQuery * query); -static GList *gst_base_auto_convert_get_or_load_factories (GstBaseAutoConvert * - self); +static GList *gst_base_auto_convert_get_or_load_filters_info (GstBaseAutoConvert + * self); G_DECLARE_FINAL_TYPE (GstBaseAutoConvertPad, gst_base_auto_convert_pad, GST, BASE_AUTO_CONVERT_PAD, GstPad); @@ -184,6 +184,112 @@ gst_base_auto_convert_element_removed (GstBin * bin, GstElement * child) g_hash_table_remove (self->elements, child); } +static void +gst_auto_convert_filter_info_free (GstAutoConvertFilterInfo * knwon_bin) +{ + g_free (knwon_bin->name); + g_free (knwon_bin->bindesc); + + g_free (knwon_bin); +} + +static gint +g_auto_convert_filter_info_compare (GstAutoConvertFilterInfo * b1, + GstAutoConvertFilterInfo * b2) +{ + gint diff; + + diff = b2->rank - b1->rank; + if (diff != 0) + return diff; + + diff = g_strcmp0 (b2->name, b1->name); + + return diff; +} + +static GstCaps * +gst_base_auto_convert_get_template_caps_for (GstElement * subbin, + GstPadDirection dir) +{ + GstElement *element = NULL; + GstPad *pad = NULL; + GstCaps *res = NULL; + + g_assert (g_list_length (subbin->sinkpads) == 1); + g_assert (g_list_length (subbin->srcpads) == 1); + if (GST_IS_BIN (subbin)) { + GstPad *ghostpad = + (dir == GST_PAD_SINK) ? subbin->sinkpads->data : subbin->srcpads->data; + GstPad *internal = gst_pad_get_single_internal_link (ghostpad); + + pad = gst_pad_get_peer (internal); + + gst_object_unref (internal); + } else { + pad = + (dir == + GST_PAD_SINK) ? gst_object_ref (subbin-> + sinkpads->data) : gst_object_ref (subbin->srcpads->data); + } + + element = GST_ELEMENT (GST_OBJECT_PARENT (pad)); + g_assert (element); + + if (!g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)), + "capsfilter")) { + g_object_get (G_OBJECT (element), "caps", &res, NULL); + } else { + res = gst_pad_get_pad_template_caps (pad); + } + gst_object_unref (pad); + + return gst_caps_make_writable (res); +} + +gboolean +gst_base_auto_convert_register_filter (GstBaseAutoConvert * self, gchar * name, + gchar * bindesc, GstRank rank) +{ + g_assert (name); + + for (GList * tmp = self->filters_info; tmp; tmp = tmp->next) { + g_return_val_if_fail (g_strcmp0 (name, + ((GstAutoConvertFilterInfo *) tmp->data)->name), FALSE); + } + + GError *err = NULL; + bindesc = g_strchomp (bindesc); + GstElement *subbin = gst_parse_bin_from_description_full (bindesc, TRUE, + NULL, GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS | GST_PARSE_FLAG_PLACE_IN_BIN, + &err); + + if (!subbin) { + GST_INFO ("Could not create subbin for %s", name); + g_free (name); + g_free (bindesc); + + return FALSE; + } + + GstAutoConvertFilterInfo *filter_info = g_new0 (GstAutoConvertFilterInfo, 1); + filter_info->sink_caps = + gst_base_auto_convert_get_template_caps_for (subbin, GST_PAD_SINK); + filter_info->src_caps = + gst_base_auto_convert_get_template_caps_for (subbin, GST_PAD_SRC); + filter_info->name = name; + filter_info->bindesc = bindesc; + filter_info->rank = rank; + + GST_OBJECT_LOCK (self); + self->filters_info = + g_list_insert_sorted (self->filters_info, filter_info, + (GCompareFunc) g_auto_convert_filter_info_compare); + GST_OBJECT_UNLOCK (self); + + return TRUE; +} + static void gst_base_auto_convert_class_init (GstBaseAutoConvertClass * klass) { @@ -201,6 +307,8 @@ gst_base_auto_convert_class_init (GstBaseAutoConvertClass * klass) gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_auto_convert_finalize); gstbin_class->element_removed = gst_base_auto_convert_element_removed; + + klass->registers_filters = TRUE; } static void @@ -255,34 +363,12 @@ gst_base_auto_convert_finalize (GObject * object) if (self->factories) gst_plugin_feature_list_free (self->factories); g_hash_table_unref (self->elements); + g_list_free_full (self->filters_info, + (GDestroyNotify) gst_auto_convert_filter_info_free); G_OBJECT_CLASS (gst_base_auto_convert_parent_class)->finalize (object); } -static GstElement * -gst_base_auto_convert_get_element_by_type (GstBaseAutoConvert * self, - GType type) -{ - GList *item, *elements; - GstElement *element = NULL; - - g_return_val_if_fail (type != 0, NULL); - - GST_BASEAUTOCONVERT_LOCK (self); - elements = g_hash_table_get_keys (self->elements); - for (item = elements; item; item = item->next) { - if (G_OBJECT_TYPE (item->data) == type) { - element = gst_object_ref (item->data); - break; - } - } - GST_BASEAUTOCONVERT_UNLOCK (self); - - g_list_free (elements); - - return element; -} - /** * get_pad_by_direction: * @element: The Element @@ -401,18 +487,28 @@ gst_base_auto_convert_get_internal_srcpad (GstBaseAutoConvert * self) static GstElement * gst_base_auto_convert_add_element (GstBaseAutoConvert * self, - GstElementFactory * factory) + GstAutoConvertFilterInfo * filter_info) { GstElement *element = NULL; InternalPads *pads; + GError *error = NULL; GST_DEBUG_OBJECT (self, "Adding element %s to the baseautoconvert bin", - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); + filter_info->name); + + element = gst_parse_bin_from_description_full (filter_info->bindesc, TRUE, + NULL, GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS | GST_PARSE_FLAG_PLACE_IN_BIN, + &error); + if (!element) { + GST_INFO_OBJECT (self, "Could not build %s: %s", filter_info->name, + error->message); + + g_error_free (error); - element = gst_element_factory_create (factory, NULL); - if (!element) return NULL; + } + gst_object_set_name (GST_OBJECT (element), filter_info->name); pads = internal_pads_new (self, GST_OBJECT_NAME (element)); g_hash_table_insert (self->elements, element, pads); @@ -434,26 +530,17 @@ gst_base_auto_convert_add_element (GstBaseAutoConvert * self, } static GstElement * -gst_base_auto_convert_get_or_make_element_from_factory (GstBaseAutoConvert * - self, GstElementFactory * factory) +gst_base_auto_convert_get_or_make_element_from_filter_info (GstBaseAutoConvert * + self, GstAutoConvertFilterInfo * nb) { GstElement *element = NULL; - GstElementFactory *loaded_factory = - GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE - (factory))); - if (!loaded_factory) - return NULL; - - element = gst_base_auto_convert_get_element_by_type (self, - gst_element_factory_get_element_type (loaded_factory)); + element = gst_bin_get_by_name (GST_BIN (self), nb->name); if (!element) { - element = gst_base_auto_convert_add_element (self, loaded_factory); + element = gst_base_auto_convert_add_element (self, nb); } - gst_object_unref (loaded_factory); - return element; } @@ -464,51 +551,25 @@ gst_base_auto_convert_get_or_make_element_from_factory (GstBaseAutoConvert * */ static gboolean -factory_can_intersect (GstBaseAutoConvert * self, - GstElementFactory * factory, GstPadDirection direction, GstCaps * caps) +filter_info_can_intersect (GstBaseAutoConvert * self, + GstAutoConvertFilterInfo * filter_info, GstPadDirection direction, + GstCaps * caps) { - const GList *templates; - gint has_direction = FALSE; - gboolean ret = FALSE; + gboolean res; + GST_LOG_OBJECT (self, "Checking if %s (bin_desc=%s) supports %s caps:", + filter_info->name, filter_info->bindesc, + direction == GST_PAD_SINK ? "sink" : "src"); + GST_LOG_OBJECT (self, "Supported caps: %" GST_PTR_FORMAT, + direction == + GST_PAD_SINK ? filter_info->sink_caps : filter_info->src_caps); + GST_LOG_OBJECT (self, "Caps: %" GST_PTR_FORMAT, caps); - g_return_val_if_fail (factory != NULL, FALSE); - g_return_val_if_fail (caps != NULL, FALSE); + res = + gst_caps_can_intersect (direction == + GST_PAD_SINK ? filter_info->sink_caps : filter_info->src_caps, caps); + GST_LOG_OBJECT (self, "Intersect result: %d", res); - templates = gst_element_factory_get_static_pad_templates (factory); - - while (templates) { - GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data; - - if (template->direction == direction) { - GstCaps *tmpl_caps = NULL; - gboolean intersect; - - /* If there is more than one pad in this direction, we return FALSE - * Only transform elements (with one sink and one source pad) - * are accepted - */ - if (has_direction) { - GST_ERROR_OBJECT (self, "Factory %p" - " has more than one static template with dir %d", - template, direction); - return FALSE; - } - has_direction = TRUE; - - tmpl_caps = gst_static_caps_get (&template->static_caps); - intersect = gst_caps_can_intersect (tmpl_caps, caps); - GST_DEBUG_OBJECT (self, "Factories %" GST_PTR_FORMAT - " static caps %" GST_PTR_FORMAT " and caps %" GST_PTR_FORMAT - " can%s intersect", factory, tmpl_caps, caps, - intersect ? "" : " not"); - gst_caps_unref (tmpl_caps); - - ret |= intersect; - } - templates = g_list_next (templates); - } - - return ret; + return res; } static gboolean @@ -633,6 +694,9 @@ gst_base_auto_convert_activate_element (GstBaseAutoConvert * self, GST_OBJECT_NAME (GST_OBJECT (element))); done: + GST_DEBUG_OBJECT (element, "Activating element %s", + res ? "succeeded" : "failed"); + gst_object_unref (element); internal_pads_unref (pads); gst_clear_object (&srcpad); @@ -677,6 +741,22 @@ gst_base_auto_convert_iterate_internal_links (GstPad * pad, GstObject * parent) return it; } +static GstAutoConvertFilterInfo * +gst_auto_convert_get_filter_info (GstBaseAutoConvert * self, + GstElement * element) +{ + GList *tmp; + + for (tmp = self->filters_info; tmp; tmp = tmp->next) { + GstAutoConvertFilterInfo *filter_info = tmp->data; + + if (!g_strcmp0 (filter_info->name, GST_OBJECT_NAME (element))) + return filter_info; + } + + return NULL; +} + /* * If there is already an internal element, it will try to call set_caps on it * @@ -689,9 +769,9 @@ static gboolean gst_base_auto_convert_sink_setcaps (GstBaseAutoConvert * self, GstCaps * caps, gboolean check_downstream) { - GList *elem; + GList *tmp; GstCaps *other_caps = NULL; - GList *factories; + GList *filters_info = NULL; GstCaps *current_caps = NULL; gboolean res = FALSE; GstElement *current_subelement = NULL; @@ -709,66 +789,81 @@ gst_base_auto_convert_sink_setcaps (GstBaseAutoConvert * self, GstCaps * caps, other_caps = gst_pad_peer_query_caps (self->srcpad, NULL); current_subelement = gst_base_auto_convert_get_subelement (self); + GST_DEBUG_OBJECT (self, + "'%" GST_PTR_FORMAT "' Setting caps to: %" GST_PTR_FORMAT + " - other caps: %" GST_PTR_FORMAT, current_subelement, caps, other_caps); if (current_subelement) { if (gst_pad_peer_query_accept_caps (self->current_internal_srcpad, caps)) { + GstAutoConvertFilterInfo *filter_info = + gst_auto_convert_get_filter_info (self, current_subelement); res = TRUE; if (other_caps) { - GstElementFactory *factory = - gst_element_get_factory (current_subelement); - - if (!factory_can_intersect (self, factory, GST_PAD_SRC, other_caps)) { + GST_DEBUG_OBJECT (self, + "Checking if known bin %s can intersect with %" GST_PTR_FORMAT, + filter_info->name, other_caps); + if (!filter_info_can_intersect (self, filter_info, GST_PAD_SRC, + other_caps)) { GST_LOG_OBJECT (self, - "Factory %s does not accept src caps %" GST_PTR_FORMAT, - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), - other_caps); + "filter_info %s does not accept src caps %" GST_PTR_FORMAT, + filter_info->name, other_caps); res = FALSE; } + GST_DEBUG_OBJECT (self, "Filter %s can intersect", filter_info->name); } if (res) { /* If we can set the new caps on the current element, * then we just get out */ - GST_ERROR_OBJECT (self, "Could set %s:%s to %" GST_PTR_FORMAT, - GST_DEBUG_PAD_NAME (self->current_internal_srcpad), caps); + GST_DEBUG_OBJECT (self, + "Could set %s:%s to %" GST_PTR_FORMAT " reusing %s", + GST_DEBUG_PAD_NAME (self->current_internal_srcpad), caps, + filter_info->name); goto get_out; + } else { + GST_DEBUG_OBJECT (self, + "Can't reuse currently configured subelement: %s", + filter_info->name); } } } if (!check_downstream) other_caps = gst_pad_peer_query_caps (self->srcpad, NULL); - /* We already queries downstream caps otherwise */ + /* We already queried downstream caps otherwise */ - factories = gst_base_auto_convert_get_or_load_factories (self); - - for (elem = factories; elem; elem = g_list_next (elem)) { - GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data); + filters_info = gst_base_auto_convert_get_or_load_filters_info (self); + for (tmp = filters_info; tmp; tmp = g_list_next (tmp)) { + GstAutoConvertFilterInfo *filter_info = tmp->data; GstElement *element; - /* Lets first check if according to the static pad templates on the factory + GST_DEBUG_OBJECT (self, "Trying %s (bin_desc=%s)", filter_info->name, + filter_info->bindesc); + /* Lets first check if according to the static pad templates on the known bin * these caps have any chance of success */ - if (!factory_can_intersect (self, factory, GST_PAD_SINK, caps)) { - GST_LOG_OBJECT (self, "Factory %s does not accept sink caps %" - GST_PTR_FORMAT, - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), caps); + if (!filter_info_can_intersect (self, filter_info, GST_PAD_SINK, caps)) { + GST_DEBUG_OBJECT (self, "Known bin %s does not accept sink caps %" + GST_PTR_FORMAT, filter_info->name, caps); continue; } if (other_caps != NULL) { - if (!factory_can_intersect (self, factory, GST_PAD_SRC, other_caps)) { - GST_LOG_OBJECT (self, - "Factory %s does not accept src caps %" GST_PTR_FORMAT, - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), - other_caps); + if (!filter_info_can_intersect (self, filter_info, GST_PAD_SRC, + other_caps)) { + GST_DEBUG_OBJECT (self, + "Known bin %s does not accept src caps %" GST_PTR_FORMAT, + filter_info->name, other_caps); continue; } + GST_DEBUG_OBJECT (self, "Filter %s can intersect", filter_info->name); } /* The element had a chance of success, lets make it */ + GST_DEBUG_OBJECT (self, "Trying bin %s", filter_info->name); element = - gst_base_auto_convert_get_or_make_element_from_factory (self, factory); + gst_base_auto_convert_get_or_make_element_from_filter_info (self, + filter_info); if (!element) continue; @@ -786,9 +881,10 @@ get_out: gst_clear_caps (&other_caps); gst_clear_caps (¤t_caps); - if (!res) + if (!res) { GST_WARNING_OBJECT (self, "Could not find a matching element for caps: %" GST_PTR_FORMAT, caps); + } return res; } @@ -870,32 +966,51 @@ compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) } static GList * -gst_base_auto_convert_get_or_load_factories (GstBaseAutoConvert * self) +gst_base_auto_convert_get_or_load_filters_info (GstBaseAutoConvert * self) { GList *all_factories; - GstBaseAutoConvertClass *klass = GST_BASE_AUTO_CONVERT_GET_CLASS (self); GST_OBJECT_LOCK (self); - if (self->factories) + if (self->filters_info) { + GST_OBJECT_UNLOCK (self); goto done; - GST_OBJECT_UNLOCK (self); + } + + if (GST_BASE_AUTO_CONVERT_GET_CLASS (self)->registers_filters) { + GST_ERROR_OBJECT (self, + "Filters should have been registered but none found"); + + GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, ("No known filter found."), + (NULL)); + + goto done; + } + + if (!self->factories) { + GST_OBJECT_UNLOCK (self); - if (klass->load_factories) { - all_factories = klass->load_factories (self); - } else { all_factories = g_list_sort (gst_registry_feature_filter (gst_registry_get (), gst_base_auto_convert_default_filter_func, FALSE, NULL), (GCompareFunc) compare_ranks); + + GST_OBJECT_LOCK (self); + self->factories = all_factories; } - - GST_OBJECT_LOCK (self); - self->factories = all_factories; - -done: GST_OBJECT_UNLOCK (self); - return self->factories; + for (GList * tmp = self->factories; tmp; tmp = g_list_next (tmp)) { + GstElementFactory *factory = tmp->data; + + gst_base_auto_convert_register_filter (self, + gst_object_get_name (GST_OBJECT (factory)), + gst_object_get_name (GST_OBJECT (factory)), + gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)) + ); + } + +done: + return self->filters_info; } /* In this case, we should almost always have an internal element, because @@ -1078,7 +1193,7 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter, GstPadDirection dir) { GstCaps *caps = NULL, *other_caps = NULL; - GList *elem, *factories; + GList *kb, *filters_info; caps = gst_caps_new_empty (); @@ -1095,35 +1210,35 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter, goto out; } - factories = gst_base_auto_convert_get_or_load_factories (self); - for (elem = factories; elem; elem = g_list_next (elem)) { - GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data); + filters_info = gst_base_auto_convert_get_or_load_filters_info (self); + for (kb = filters_info; kb; kb = g_list_next (kb)) { + GstAutoConvertFilterInfo *filter_info = kb->data; GstElement *element = NULL; GstCaps *element_caps; InternalPads *pads; if (filter) { - if (!factory_can_intersect (self, factory, dir, filter)) { + if (!filter_info_can_intersect (self, filter_info, dir, filter)) { GST_LOG_OBJECT (self, - "Factory %s does not accept src caps %" GST_PTR_FORMAT, - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), - other_caps); + "Bin %s does not accept %s caps %" GST_PTR_FORMAT, + filter_info->name, dir == GST_PAD_SRC ? "src" : "sink", other_caps); continue; } } if (other_caps != NULL) { - if (!factory_can_intersect (self, factory, + if (!filter_info_can_intersect (self, filter_info, dir == GST_PAD_SINK ? GST_PAD_SRC : GST_PAD_SINK, other_caps)) { GST_LOG_OBJECT (self, - "Factory %s does not accept src caps %" GST_PTR_FORMAT, - gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), - other_caps); + "%s does not accept %s caps %" GST_PTR_FORMAT, + filter_info->name, + dir == GST_PAD_SINK ? "src" : "sink", other_caps); continue; } - element = gst_base_auto_convert_get_or_make_element_from_factory (self, - factory); + element = + gst_base_auto_convert_get_or_make_element_from_filter_info (self, + filter_info); if (element == NULL) continue; @@ -1141,24 +1256,16 @@ gst_base_auto_convert_getcaps (GstBaseAutoConvert * self, GstCaps * filter, if (gst_caps_is_any (caps)) goto out; } else { - const GList *tmp; + GstCaps *static_caps = + dir == GST_PAD_SRC ? filter_info->src_caps : filter_info->sink_caps; - for (tmp = gst_element_factory_get_static_pad_templates (factory); - tmp; tmp = g_list_next (tmp)) { - GstStaticPadTemplate *template = tmp->data; - - if (GST_PAD_TEMPLATE_DIRECTION (template) == dir) { - GstCaps *static_caps = gst_static_pad_template_get_caps (template); - - if (static_caps) { - caps = gst_caps_merge (caps, static_caps); - } - - /* Early out, any is absorbing */ - if (gst_caps_is_any (caps)) - goto out; - } + if (static_caps) { + caps = gst_caps_merge (caps, static_caps); } + + /* Early out, any is absorbing */ + if (gst_caps_is_any (caps)) + goto out; } } @@ -1191,7 +1298,7 @@ gst_base_auto_convert_src_event (GstPad * pad, GstObject * parent, gst_object_unref (internal_sinkpad); } else if (GST_EVENT_TYPE (event) != GST_EVENT_RECONFIGURE) { GST_WARNING_OBJECT (self, - "Got upstream event while no element was selected," "forwarding."); + "Got upstream event while no element was selected, forwarding."); ret = gst_pad_push_event (self->sinkpad, event); } else gst_event_unref (event); @@ -1339,3 +1446,14 @@ gst_base_auto_convert_internal_src_query (GstPad * pad, GstObject * parent, return gst_pad_peer_query (self->sinkpad, query); } + + +void +gst_base_auto_convert_reset_filters (GstBaseAutoConvert * self) +{ + GST_OBJECT_LOCK (self); + g_list_free_full (self->filters_info, + (GDestroyNotify) gst_auto_convert_filter_info_free); + self->filters_info = NULL; + GST_OBJECT_UNLOCK (self); +} diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.h b/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.h index 7cdcd4395c..d59fb8d6bd 100644 --- a/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.h +++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstbaseautoconvert.h @@ -42,6 +42,7 @@ struct _GstBaseAutoConvert GstBin bin; /* we extend GstBin */ GList *factories; + GList *filters_info; GstPad *sinkpad; GstPad *srcpad; @@ -54,17 +55,36 @@ struct _GstBaseAutoConvert GstPad *current_internal_srcpad; GstPad *current_internal_sinkpad; - GHashTable * elements; + GHashTable *elements; }; +/* This structure is used to allow handling random bin from their description + without needing to register a factory. The data it contains is pretty similar + but is specific for filters (1sinkpad and 1 srcpad). +*/ +typedef struct +{ + /* Name of the filter, each instance of should have that name */ + gchar *name; + gchar *bindesc; + GstRank rank; + GstCaps *sink_caps; + GstCaps *src_caps; +} GstAutoConvertFilterInfo; + struct _GstBaseAutoConvertClass { GstBinClass parent_class; - GList* (*load_factories)(GstBaseAutoConvert *base_autoconvert); + gboolean registers_filters; }; G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstBaseAutoConvert, gst_object_unref) GType gst_base_auto_convert_get_type (void); +gboolean +gst_base_auto_convert_register_filter(GstBaseAutoConvert *self, gchar *name, + gchar * bindesc, GstRank rank); +void gst_base_auto_convert_reset_filters (GstBaseAutoConvert * self); + G_END_DECLS diff --git a/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate.validatetest b/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate.validatetest index 2077d2d4e0..7c6a74cbe4 100644 --- a/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate.validatetest +++ b/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate.validatetest @@ -3,7 +3,7 @@ meta, "gltestsrc ! gldownload ! autovideoconvert name=convert ! capsfilter name=capsfilter caps=\"video/x-raw(memory:GLMemory)\" ! fakevideosink name=sink", }, configs = { - "$(validateflow), pad=convert:src, record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream},buffer={meta}\"", + "$(validateflow), pad=\"^convert:src$\", record-buffers=true, ignored-fields=\"stream-start={stream-id,group-id,stream},buffer={meta}\"", } crank-clock, repeat=2 @@ -15,8 +15,9 @@ foreach, "video/x-raw", >, actions = { + [checkpoint, text="Setup capsfilter caps=$(caps)"], [set-properties, capsfilter::caps="$(caps)"], [crank-clock, repeat=2], [wait, on-clock=true], } -stop \ No newline at end of file +stop diff --git a/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-convert-src-expected b/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-^convert-src569JNRXZghikmsexpected similarity index 82% rename from subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-convert-src-expected rename to subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-^convert-src569JNRXZghikmsexpected index df1f9918a5..bc3c358f6b 100644 --- a/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-convert-src-expected +++ b/subprojects/gst-plugins-bad/tests/validate/autovideoconvert/renegotiate/flow-expectations/log-^convert-src569JNRXZghikmsexpected @@ -4,12 +4,21 @@ event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, s buffer: pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont buffer: pts=0:00:00.033333333, dur=0:00:00.033333333 buffer: pts=0:00:00.066666666, dur=0:00:00.033333334 -event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320; + +CHECKPOINT: Setup capsfilter caps=video/x-raw + +event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, width=(int)320; buffer: pts=0:00:00.100000000, dur=0:00:00.033333333 buffer: pts=0:00:00.133333333, dur=0:00:00.033333333 + +CHECKPOINT: Setup capsfilter caps=video/x-raw(memory:GLMemory) + event caps: video/x-raw(memory:GLMemory), format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320; buffer: pts=0:00:00.166666666, dur=0:00:00.033333334 buffer: pts=0:00:00.200000000, dur=0:00:00.033333333 -event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, texture-target=(string)2D, width=(int)320; + +CHECKPOINT: Setup capsfilter caps=video/x-raw + +event caps: video/x-raw, format=(string)RGBA, framerate=(fraction)30/1, height=(int)240, width=(int)320; buffer: pts=0:00:00.233333333, dur=0:00:00.033333333 buffer: pts=0:00:00.266666666, dur=0:00:00.033333334