ges: framepositioner: Expose positioning properties as doubles
authorThibault Saunier <tsaunier@igalia.com>
Tue, 27 Feb 2024 17:00:04 +0000 (14:00 -0300)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 29 Feb 2024 00:56:30 +0000 (00:56 +0000)
Making it possible to properly handle compositors that have those
properties as doubles and handle antialiasing.

Internally we were handling those values as doubles in framepositioner,
so expose new properties so user can set values as doubles also.

This changes the GESFramePositionMeta API but we are still on time for 1.24

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6241>

girs/GES-1.0.gir
subprojects/gst-editing-services/ges/ges-frame-composition-meta.h
subprojects/gst-editing-services/ges/ges-smart-video-mixer.c
subprojects/gst-editing-services/ges/ges-track-element.c
subprojects/gst-editing-services/ges/ges-utils.c
subprojects/gst-editing-services/ges/ges-video-source.c
subprojects/gst-editing-services/ges/gesvideoscale.c
subprojects/gst-editing-services/ges/gstframepositioner.c
subprojects/gst-editing-services/ges/gstframepositioner.h

index 0dfba058db78c2c6d219da306121815d58e51b3b..f1c5dcabc484bb61b414f24c426e7a3c9fabcf20 100644 (file)
@@ -4487,21 +4487,21 @@ composition.</doc>
       </field>
       <field name="posx" writable="1">
         <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-frame-composition-meta.h">The desired x position.</doc>
-        <type name="gint" c:type="gint"/>
+        <type name="gdouble" c:type="gdouble"/>
       </field>
       <field name="posy" writable="1">
         <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-frame-composition-meta.h">The desired y position.</doc>
-        <type name="gint" c:type="gint"/>
+        <type name="gdouble" c:type="gdouble"/>
       </field>
       <field name="height" writable="1">
         <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-frame-composition-meta.h">The desired height of the video. -1 means that no scaling should be
 applied.</doc>
-        <type name="gint" c:type="gint"/>
+        <type name="gdouble" c:type="gdouble"/>
       </field>
       <field name="width" writable="1">
         <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-frame-composition-meta.h">The desired width of the video. -1 means that no scaling should beapplied
 applied.</doc>
-        <type name="gint" c:type="gint"/>
+        <type name="gdouble" c:type="gdouble"/>
       </field>
       <field name="zorder" writable="1">
         <doc xml:space="preserve" filename="../subprojects/gst-editing-services/ges/ges-frame-composition-meta.h">The desired z order.</doc>
index 82f7b55c89ebcc2f3e091b0acda22a335663333d..581d36a0972ddb142263a9aa2c0ae317acae0a1f 100644 (file)
@@ -61,10 +61,10 @@ struct _GESFrameCompositionMeta {
   GstMeta meta;
 
   gdouble alpha;
-  gint posx;
-  gint posy;
-  gint height;
-  gint width;
+  gdouble posx;
+  gdouble posy;
+  gdouble height;
+  gdouble width;
   guint zorder;
   gint operator;
 };
index 3a8b9d608c9fef797710bbef61cefebabcba528f..70acced461e062b5a510d8c4c613a557174edaf7 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 #endif
 
+#include <math.h>
 #include "gstframepositioner.h"
 #include "ges-frame-composition-meta.h"
 #include "ges-types.h"
@@ -38,6 +39,11 @@ struct _GESSmartMixerPad
 
   gdouble alpha;
   GstSegment segment;
+
+  GParamSpec *width_pspec;
+  GParamSpec *height_pspec;
+  GParamSpec *xpos_pspec;
+  GParamSpec *ypos_pspec;
 };
 
 struct _GESSmartMixerPadClass
@@ -53,6 +59,18 @@ enum
 
 G_DEFINE_TYPE (GESSmartMixerPad, ges_smart_mixer_pad, GST_TYPE_GHOST_PAD);
 
+static void
+ges_smart_mixer_notify_wrapped_pad (GESSmartMixerPad * self,
+    GstPad * real_mixer_pad)
+{
+  GObjectClass *klass = G_OBJECT_GET_CLASS (real_mixer_pad);
+
+  self->width_pspec = g_object_class_find_property (klass, "width");
+  self->height_pspec = g_object_class_find_property (klass, "height");
+  self->xpos_pspec = g_object_class_find_property (klass, "xpos");
+  self->ypos_pspec = g_object_class_find_property (klass, "ypos");
+}
+
 static void
 ges_smart_mixer_pad_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec)
@@ -240,13 +258,35 @@ set_pad_properties_from_composition_meta (GstPad * mixer_pad,
     g_object_set (mixer_pad, "alpha", meta->alpha * transalpha, NULL);
   }
 
-  g_object_set (mixer_pad, "xpos", meta->posx, "ypos", meta->posy, NULL);
+  if (G_PARAM_SPEC_VALUE_TYPE (ghost->xpos_pspec) == G_TYPE_INT) {
+    g_object_set (mixer_pad, "xpos", (gint) round (meta->posx), "ypos",
+        (gint) round (meta->posy), NULL);
+  } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->xpos_pspec) == G_TYPE_FLOAT) {
+    g_object_set (mixer_pad, "xpos", (gfloat) meta->posx, "ypos",
+        (gfloat) meta->posy, NULL);
+  } else {
+    g_object_set (mixer_pad, "xpos", meta->posx, "ypos", meta->posy, NULL);
+  }
 
-  if (meta->width >= 0)
-    g_object_set (mixer_pad, "width", meta->width, NULL);
+  if (meta->width >= 0) {
+    if (G_PARAM_SPEC_VALUE_TYPE (ghost->width_pspec) == G_TYPE_INT) {
+      g_object_set (mixer_pad, "width", (gint) round (meta->width), NULL);
+    } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->width_pspec) == G_TYPE_FLOAT) {
+      g_object_set (mixer_pad, "width", (gfloat) meta->width, NULL);
+    } else {
+      g_object_set (mixer_pad, "width", meta->width, NULL);
+    }
+  }
 
-  if (meta->height >= 0)
-    g_object_set (mixer_pad, "height", meta->height, NULL);
+  if (meta->height >= 0) {
+    if (G_PARAM_SPEC_VALUE_TYPE (ghost->height_pspec) == G_TYPE_INT) {
+      g_object_set (mixer_pad, "height", (gint) round (meta->height), NULL);
+    } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->height_pspec) == G_TYPE_FLOAT) {
+      g_object_set (mixer_pad, "height", (gfloat) meta->height, NULL);
+    } else {
+      g_object_set (mixer_pad, "height", meta->height, NULL);
+    }
+  }
 
   if (self->ABI.abi.has_operator)
     g_object_set (mixer_pad, "operator", meta->operator, NULL);
@@ -294,6 +334,8 @@ _request_new_pad (GstElement * element, GstPadTemplate * templ,
       "direction", GST_PAD_DIRECTION (infos->mixer_pad), NULL);
   infos->ghostpad = ghost;
   gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghost), infos->mixer_pad);
+  ges_smart_mixer_notify_wrapped_pad (GES_SMART_MIXER_PAD (ghost),
+      infos->real_mixer_pad);
   gst_pad_set_active (ghost, TRUE);
   if (!gst_element_add_pad (GST_ELEMENT (self), ghost))
     goto could_not_add;
index bbcc14caa4032808712730cb850c5e385a026ddd..60c0691974f92452c6953e03da3d9edff2853547 100644 (file)
@@ -56,6 +56,7 @@
 #endif
 
 #include "ges-internal.h"
+#include "gstframepositioner.h"
 #include "ges-extractable.h"
 #include "ges-track-element.h"
 #include "ges-clip.h"
@@ -1913,10 +1914,12 @@ ges_track_element_set_control_source (GESTrackElement * object,
     goto done;
   }
 
-  /* First remove existing binding */
-  if (ges_track_element_remove_control_binding (object, property_name))
-    GST_LOG_OBJECT (object, "Removed old binding for property %s",
-        property_name);
+  if (GST_IS_FRAME_POSITIONNER (element)) {
+    if (!gst_frame_positioner_check_can_add_binding (GST_FRAME_POSITIONNER
+            (element), property_name)) {
+      goto done;
+    }
+  }
 
   if (direct_absolute)
     binding = gst_direct_control_binding_new_absolute (GST_OBJECT (element),
index efc0c000e7c14736851f60d20eafe3934f318d3d..8e6218d165e2338d06fc478da9b49abbcb36b30f 100644 (file)
@@ -192,6 +192,47 @@ find_compositor (GstPluginFeature * feature, gpointer udata)
             (loaded_feature)), GST_TYPE_AGGREGATOR);
   }
 
+  if (res) {
+    const gchar *needed_props[] = { "width", "height", "xpos", "ypos" };
+    GObjectClass *klass =
+        g_type_class_ref (gst_element_factory_get_element_type
+        (GST_ELEMENT_FACTORY (loaded_feature)));
+    GstPadTemplate *templ =
+        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass),
+        "sink_%u");
+
+    g_type_class_unref (klass);
+    if (!templ) {
+      GST_INFO_OBJECT (loaded_feature, "No sink template found, ignoring");
+      res = FALSE;
+      goto done;
+    }
+
+    GType pad_type;
+    g_object_get (templ, "gtype", &pad_type, NULL);
+    klass = g_type_class_ref (pad_type);
+    for (gint i = 0; i < G_N_ELEMENTS (needed_props); i++) {
+      GParamSpec *pspec;
+
+      if (!(pspec = g_object_class_find_property (klass, needed_props[i]))) {
+        GST_INFO_OBJECT (loaded_feature, "No property %s found, ignoring",
+            needed_props[i]);
+        res = FALSE;
+        break;
+      }
+
+      if (pspec->value_type != G_TYPE_INT && pspec->value_type != G_TYPE_FLOAT
+          && pspec->value_type != G_TYPE_DOUBLE) {
+        GST_INFO_OBJECT (loaded_feature,
+            "Property %s is not of type int or float, or double, ignoring",
+            needed_props[i]);
+        res = FALSE;
+        break;
+      }
+    }
+    g_type_class_unref (klass);
+  }
+
 done:
   gst_clear_object (&elem);
   gst_object_unref (loaded_feature);
index 9bae5f123b684d1c5601d8a2de3091afab985870..aeb92df6884ba6f4250b9e1198c527abe3c511f5 100644 (file)
@@ -115,7 +115,9 @@ ges_video_source_create_filters (GESVideoSource * self, GPtrArray * elements,
   GESTrackElement *trksrc = GES_TRACK_ELEMENT (self);
   GstElement *positioner, *videoflip, *capsfilter, *videorate;
   const gchar *positioner_props[]
-  = { "alpha", "posx", "posy", "width", "height", "operator", NULL };
+      = { "alpha", "posx", "fposx", "posy", "fposy", "width", "fwidth",
+    "height", "fheight", "operator", NULL
+  };
   const gchar *videoflip_props[] = { "video-direction", NULL };
   gchar *ename = NULL;
 
index 3ae0810c302cd19d1ac6e230a18d9039d783bb07..29cba3d94d0173638d934f87f18f917865b142d5 100644 (file)
@@ -22,6 +22,7 @@
 #endif
 
 #include <gst/gst.h>
+#include <math.h>
 
 #include "ges-frame-composition-meta.h"
 
@@ -96,7 +97,8 @@ chain (GstPad * pad, GESVideoScale * self, GstBuffer * buffer)
     if (meta->height != self->height || meta->width != self->width) {
       GST_OBJECT_UNLOCK (self);
 
-      set_dimension (self, meta->width, meta->height);
+      set_dimension (self, (gint) round (meta->width),
+          (gint) round (meta->height));
     } else {
       GST_OBJECT_UNLOCK (self);
     }
index 16356204f258991eaeae335d9b3d2e200442b69d..e7d416922c02e2bcfda4d9a9aaf5f25a01f9f612 100644 (file)
@@ -48,11 +48,20 @@ enum
 {
   PROP_0,
   PROP_ALPHA,
+
   PROP_POSX,
+  PROP_FPOSX,
+
   PROP_POSY,
-  PROP_ZORDER,
+  PROP_FPOSY,
+
   PROP_WIDTH,
+  PROP_FWIDTH,
+
   PROP_HEIGHT,
+  PROP_FHEIGHT,
+
+  PROP_ZORDER,
   PROP_OPERATOR,
   PROP_LAST,
 };
@@ -143,9 +152,16 @@ is_user_positionned (GstFramePositioner * self)
   gint i;
   GParamSpec *positioning_props[] = {
     properties[PROP_WIDTH],
+    properties[PROP_FWIDTH],
+
     properties[PROP_HEIGHT],
+    properties[PROP_FHEIGHT],
+
     properties[PROP_POSX],
+    properties[PROP_FPOSX],
+
     properties[PROP_POSY],
+    properties[PROP_FPOSY],
   };
 
   if (self->user_positioned)
@@ -219,13 +235,22 @@ reposition_properties (GstFramePositioner * pos, gint old_track_width,
     gint old_track_height)
 {
   gint i;
+  /* *INDENT-OFF* */
   RepositionPropertyData props_data[] = {
+    {&pos->width, old_track_width, pos->track_width, properties[PROP_FWIDTH]},
     {&pos->width, old_track_width, pos->track_width, properties[PROP_WIDTH]},
-    {&pos->height, old_track_height, pos->track_height,
-        properties[PROP_HEIGHT]},
+
+    {&pos->height, old_track_height, pos->track_height, properties[PROP_FHEIGHT]},
+    {&pos->height, old_track_height, pos->track_height, properties[PROP_HEIGHT]},
+
+    {&pos->posx, old_track_width, pos->track_width, properties[PROP_FPOSX]},
     {&pos->posx, old_track_width, pos->track_width, properties[PROP_POSX]},
+
+    {&pos->posy, old_track_height, pos->track_height, properties[PROP_FPOSY]},
     {&pos->posy, old_track_height, pos->track_height, properties[PROP_POSY]},
   };
+  /* *INDENT-ON* */
+
 
   for (i = 0; i < G_N_ELEMENTS (props_data); i++) {
     GList *values, *tmp;
@@ -236,8 +261,10 @@ reposition_properties (GstFramePositioner * pos, gint old_track_width,
     GstControlBinding *binding =
         gst_object_get_control_binding (GST_OBJECT (pos), d.pspec->name);
 
-    *(d.value) =
-        *(d.value) * (gdouble) d.track_value / (gdouble) d.old_track_value;
+    if (G_PARAM_SPEC_VALUE_TYPE (d.pspec) == G_TYPE_FLOAT) {
+      *(d.value) =
+          *(d.value) * (gdouble) d.track_value / (gdouble) d.old_track_value;
+    }
 
     if (!binding)
       continue;
@@ -523,9 +550,19 @@ gst_frame_positioner_class_init (GstFramePositionerClass * klass)
    * The desired x position for the stream.
    */
   properties[PROP_POSX] =
-      g_param_spec_int ("posx", "posx", "x position of the stream", MIN_PIXELS,
-      MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+      g_param_spec_int ("posx", "posx", "x position of the stream",
+      MIN_PIXELS, MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
 
+  /**
+   * gstframepositioner:fposx:
+   *
+   * The desired x position for the stream.
+   */
+  properties[PROP_FPOSX] =
+      g_param_spec_float ("fposx", "fposx", "x position of the stream in float",
+      MIN_PIXELS, MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
 
   /**
    * gstframepositioner:posy:
@@ -533,8 +570,20 @@ gst_frame_positioner_class_init (GstFramePositionerClass * klass)
    * The desired y position for the stream.
    */
   properties[PROP_POSY] =
-      g_param_spec_int ("posy", "posy", "y position of the stream", MIN_PIXELS,
-      MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+      g_param_spec_int ("posy", "posy", "y position of the stream",
+      MIN_PIXELS, MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+
+  /**
+   * gstframepositioner:fposy:
+   *
+   * The desired y position for the stream.
+   */
+  properties[PROP_FPOSY] =
+      g_param_spec_float ("fposy", "fposy", "y position of the stream in float",
+      MIN_PIXELS, MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
 
   /**
    * gstframepositioner:zorder:
@@ -552,8 +601,20 @@ gst_frame_positioner_class_init (GstFramePositionerClass * klass)
    * Set to 0 if size is not mandatory, will be set to width of the current track.
    */
   properties[PROP_WIDTH] =
-      g_param_spec_int ("width", "width", "width of the source", 0, MAX_PIXELS,
-      0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+      g_param_spec_int ("width", "width", "width of the source", 0,
+      MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+  /**
+   * gesframepositioner:fwidth:
+   *
+   * The desired width for that source.
+   * Set to 0 if size is not mandatory, will be set to width of the current track.
+   */
+  properties[PROP_FWIDTH] =
+      g_param_spec_float ("fwidth", "fwidth", "width of the source in float", 0,
+      MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
 
   /**
    * gesframepositioner:height:
@@ -563,7 +624,19 @@ gst_frame_positioner_class_init (GstFramePositionerClass * klass)
    */
   properties[PROP_HEIGHT] =
       g_param_spec_int ("height", "height", "height of the source", 0,
-      MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+      MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+  /**
+   * gesframepositioner:fheight:
+   *
+   * The desired height for that source.
+   * Set to 0 if size is not mandatory, will be set to height of the current track.
+   */
+  properties[PROP_FHEIGHT] =
+      g_param_spec_float ("fheight", "fheight", "height of the source in float",
+      0, MAX_PIXELS, 0,
+      G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
 
   /**
    * gesframepositioner:operator:
@@ -635,10 +708,18 @@ gst_frame_positioner_set_property (GObject * object, guint property_id,
       framepositioner->posx = g_value_get_int (value);
       framepositioner->user_positioned = TRUE;
       break;
+    case PROP_FPOSX:
+      framepositioner->posx = g_value_get_float (value);
+      framepositioner->user_positioned = TRUE;
+      break;
     case PROP_POSY:
       framepositioner->posy = g_value_get_int (value);
       framepositioner->user_positioned = TRUE;
       break;
+    case PROP_FPOSY:
+      framepositioner->posy = g_value_get_float (value);
+      framepositioner->user_positioned = TRUE;
+      break;
     case PROP_ZORDER:
       framepositioner->zorder = g_value_get_uint (value);
       break;
@@ -648,12 +729,24 @@ gst_frame_positioner_set_property (GObject * object, guint property_id,
       gst_frame_positioner_update_properties (framepositioner, track_mixing,
           0, 0);
       break;
+    case PROP_FWIDTH:
+      framepositioner->user_positioned = TRUE;
+      framepositioner->width = g_value_get_float (value);
+      gst_frame_positioner_update_properties (framepositioner, track_mixing,
+          0, 0);
+      break;
     case PROP_HEIGHT:
       framepositioner->user_positioned = TRUE;
       framepositioner->height = g_value_get_int (value);
       gst_frame_positioner_update_properties (framepositioner, track_mixing,
           0, 0);
       break;
+    case PROP_FHEIGHT:
+      framepositioner->user_positioned = TRUE;
+      framepositioner->height = g_value_get_float (value);
+      gst_frame_positioner_update_properties (framepositioner, track_mixing,
+          0, 0);
+      break;
     case PROP_OPERATOR:
       framepositioner->operator = g_value_get_enum (value);
       gst_frame_positioner_update_properties (framepositioner, track_mixing,
@@ -671,7 +764,7 @@ gst_frame_positioner_get_property (GObject * object, guint property_id,
     GValue * value, GParamSpec * pspec)
 {
   GstFramePositioner *pos = GST_FRAME_POSITIONNER (object);
-  gint real_width, real_height;
+  gdouble real_width, real_height;
 
   switch (property_id) {
     case PROP_ALPHA:
@@ -680,9 +773,15 @@ gst_frame_positioner_get_property (GObject * object, guint property_id,
     case PROP_POSX:
       g_value_set_int (value, round (pos->posx));
       break;
+    case PROP_FPOSX:
+      g_value_set_float (value, pos->posx);
+      break;
     case PROP_POSY:
       g_value_set_int (value, round (pos->posy));
       break;
+    case PROP_FPOSY:
+      g_value_set_float (value, pos->posy);
+      break;
     case PROP_ZORDER:
       g_value_set_uint (value, pos->zorder);
       break;
@@ -690,18 +789,32 @@ gst_frame_positioner_get_property (GObject * object, guint property_id,
       if (pos->scale_in_compositor) {
         g_value_set_int (value, round (pos->width));
       } else {
-        real_width =
-            pos->width > 0 ? round (pos->width) : round (pos->track_width);
-        g_value_set_int (value, real_width);
+        real_width = pos->width > 0 ? pos->width : pos->track_width;
+        g_value_set_int (value, round (real_width));
+      }
+      break;
+    case PROP_FWIDTH:
+      if (pos->scale_in_compositor) {
+        g_value_set_float (value, pos->width);
+      } else {
+        real_width = pos->width > 0 ? pos->width : pos->track_width;
+        g_value_set_float (value, real_width);
       }
       break;
     case PROP_HEIGHT:
       if (pos->scale_in_compositor) {
         g_value_set_int (value, round (pos->height));
       } else {
-        real_height =
-            pos->height > 0 ? round (pos->height) : round (pos->track_height);
-        g_value_set_int (value, real_height);
+        real_height = pos->height > 0 ? pos->height : pos->track_height;
+        g_value_set_int (value, round (real_height));
+      }
+      break;
+    case PROP_FHEIGHT:
+      if (pos->scale_in_compositor) {
+        g_value_set_float (value, pos->height);
+      } else {
+        real_height = pos->height > 0 ? pos->height : pos->track_height;
+        g_value_set_float (value, real_height);
       }
       break;
     case PROP_OPERATOR:
@@ -728,13 +841,54 @@ gst_frame_positioner_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
 
   GST_OBJECT_LOCK (framepositioner);
   meta->alpha = framepositioner->alpha;
-  meta->posx = round (framepositioner->posx);
-  meta->posy = round (framepositioner->posy);
-  meta->width = round (framepositioner->width);
-  meta->height = round (framepositioner->height);
+  meta->posx = framepositioner->posx;
+  meta->posy = framepositioner->posy;
+  meta->width = framepositioner->width;
+  meta->height = framepositioner->height;
   meta->zorder = framepositioner->zorder;
   meta->operator = framepositioner->operator;
   GST_OBJECT_UNLOCK (framepositioner);
 
   return GST_FLOW_OK;
 }
+
+gboolean
+gst_frame_positioner_check_can_add_binding (GstFramePositioner * self,
+    const gchar * property_name)
+{
+  gint i = 0;
+  const gchar *checked_prop = NULL;
+  const gchar *props[][2] = {
+    {"posx", "fposx"},
+    {"posy", "fposy"},
+    {"width", "fwidth"},
+    {"height", "fheight"},
+  };
+
+
+  for (i = 0; i < G_N_ELEMENTS (props); i++) {
+    if (!g_strcmp0 (property_name, props[i][0])) {
+      checked_prop = props[i][1];
+      break;
+    } else if (!g_strcmp0 (property_name, props[i][1])) {
+      checked_prop = props[i][0];
+      break;
+    }
+  }
+
+  if (!checked_prop)
+    return TRUE;
+
+  GstControlBinding *b =
+      gst_object_get_control_binding (GST_OBJECT (self), checked_prop);
+  if (b) {
+    gst_object_unref (b);
+    GST_WARNING_OBJECT (self,
+        "Can't add control binding for %s as %s already has one", property_name,
+        checked_prop);
+
+    return FALSE;
+  }
+
+  return TRUE;
+}
index d7ce135b79d659cab769d085d3a0f83cfc28977c..7ed985a8b4b5811d5d6d971a76677e0b7d0f85cd 100644 (file)
@@ -72,6 +72,7 @@ struct _GstFramePositionerClass
   GstBaseTransformClass base_framepositioner_class;
 };
 
+G_GNUC_INTERNAL gboolean gst_frame_positioner_check_can_add_binding (GstFramePositioner *self, const gchar *property_name);
 G_GNUC_INTERNAL GType gst_compositor_operator_get_type_and_default_value (int *default_operator_value);
 G_GNUC_INTERNAL void ges_frame_positioner_set_source_and_filter (GstFramePositioner *pos,
                                                  GESTrackElement *trksrc,