From f817afb86545587dee42ed05a3388331464f68d8 Mon Sep 17 00:00:00 2001
From: Thibault Saunier <tsaunier@igalia.com>
Date: Mon, 28 Mar 2022 19:09:56 +0200
Subject: [PATCH] auto: Expose colorspace and scaler elements for well know
 elements

And require Scaler in the class of elements to be plugged by
autovideoconvert

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/899>
---
 .../gst/autoconvert/gstautovideoconvert.c     | 152 +++++++++++++++++-
 1 file changed, 149 insertions(+), 3 deletions(-)

diff --git a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c
index 4c084ea4a9..c722b83e0d 100644
--- a/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c
+++ b/subprojects/gst-plugins-bad/gst/autoconvert/gstautovideoconvert.c
@@ -67,9 +67,8 @@ gst_auto_video_convert_element_filter (GstPluginFeature * feature,
   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, "Converter") &&
-      strstr (klass, "Video")) {
+  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)));
@@ -78,11 +77,158 @@ gst_auto_video_convert_element_filter (GstPluginFeature * feature,
   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 <tsaunier@igalia.com>");
+
+  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 (&registered_well_known_bins)) {
+    register_well_known_bins ();
+    g_once_init_leave (&registered_well_known_bins, (gpointer) TRUE);
+  }
 
   /* get the feature list using the filter */
   result = gst_registry_feature_filter (gst_registry_get (),