gdkpixbufoverlay: add "positioning-mode" property to allow absolute positions
authorTim-Philipp Müller <tim@centricular.com>
Thu, 25 Dec 2014 14:53:09 +0000 (14:53 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Thu, 25 Dec 2014 15:38:37 +0000 (15:38 +0000)
Set positioning-mode=pixels-absolute to allow positioning with
absolute coordinates, meaning negative x/y offsets will be
interpreted as being to the left/above the video frame instead
of being interpreted as relative to the right/bottom edge of
the video frame (which is a silly default, but that's how it is).

This means we can nicely slide images into and out of the frame,
see gdkpixbufoverlay-test.

https://bugzilla.gnome.org/show_bug.cgi?id=739566

ext/gdk_pixbuf/gstgdkpixbufoverlay.c
ext/gdk_pixbuf/gstgdkpixbufoverlay.h

index 34b4f0a192697f8bdede1652e03db792ffabf0a5..8da40761d6008e17c4be1f432354934d3aeeb174 100644 (file)
@@ -81,6 +81,7 @@ enum
   PROP_0,
   PROP_LOCATION,
   PROP_PIXBUF,
+  PROP_POSITIONING_MODE,
   PROP_OFFSET_X,
   PROP_OFFSET_Y,
   PROP_RELATIVE_X,
@@ -97,6 +98,10 @@ enum
     "IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, " \
     "GRAY8, GRAY16_BE, GRAY16_LE }"
 
+/* FIXME 2.0: change to absolute positioning */
+#define DEFAULT_POSITIONING_MODE \
+    GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES
+
 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
@@ -112,6 +117,29 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
 G_DEFINE_TYPE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay,
     GST_TYPE_VIDEO_FILTER);
 
+#define GST_TYPE_GDK_PIXBUF_POSITIONING_MODE \
+    (gst_gdk_pixbuf_positioning_mode_get_type())
+
+static GType
+gst_gdk_pixbuf_positioning_mode_get_type (void)
+{
+  static const GEnumValue pos_modes[] = {
+    {GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES,
+        "pixels-relative-to-edges", "pixels-relative-to-edges"},
+    {GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE, "pixels-absolute",
+        "pixels-absolute"},
+    {0, NULL, NULL},
+  };
+
+  static GType type;            /* 0 */
+
+  if (!type) {
+    type = g_enum_register_static ("GstGdkPixbufPositioningMode", pos_modes);
+  }
+
+  return type;
+}
+
 static void
 gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass)
 {
@@ -193,6 +221,24 @@ gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass)
       g_param_spec_object ("pixbuf", "Pixbuf", "GdkPixbuf object to render",
           GDK_TYPE_PIXBUF, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
           | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  /**
+   * GstGdkPixbufOverlay:positioning-mode:
+   *
+   * Positioning mode of offset-x and offset-y properties. Determines how
+   * negative x/y offsets will be interpreted. By default negative values
+   * are for positioning relative to the right/bottom edge of the video
+   * image, but you can use this property to select absolute positioning
+   * relative to a (0, 0) origin in the top-left corner. That way negative
+   * offsets will be to the left/above the video image, which allows you to
+   * smoothly slide logos into and out of the frame if desired.
+   *
+   * Since: 1.6
+   */
+  g_object_class_install_property (gobject_class, PROP_POSITIONING_MODE,
+      g_param_spec_enum ("positioning-mode", "Positioning mode",
+          "Positioning mode of offset-x and offset-y properties",
+          GST_TYPE_GDK_PIXBUF_POSITIONING_MODE, DEFAULT_POSITIONING_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sink_template));
@@ -216,6 +262,8 @@ gst_gdk_pixbuf_overlay_init (GstGdkPixbufOverlay * overlay)
   overlay->relative_x = 0.0;
   overlay->relative_y = 0.0;
 
+  overlay->positioning_mode = DEFAULT_POSITIONING_MODE;
+
   overlay->overlay_width = 0;
   overlay->overlay_height = 0;
 
@@ -281,6 +329,10 @@ gst_gdk_pixbuf_overlay_set_property (GObject * object, guint property_id,
       overlay->alpha = g_value_get_double (value);
       overlay->update_composition = TRUE;
       break;
+    case PROP_POSITIONING_MODE:
+      overlay->positioning_mode = g_value_get_enum (value);
+      overlay->update_composition = TRUE;
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -325,6 +377,9 @@ gst_gdk_pixbuf_overlay_get_property (GObject * object, guint property_id,
     case PROP_ALPHA:
       g_value_set_double (value, overlay->alpha);
       break;
+    case PROP_POSITIONING_MODE:
+      g_value_set_enum (value, overlay->positioning_mode);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -479,6 +534,7 @@ gst_gdk_pixbuf_overlay_set_info (GstVideoFilter * filter, GstCaps * incaps,
 static void
 gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay)
 {
+  GstGdkPixbufPositioningMode positioning_mode;
   GstVideoOverlayComposition *comp;
   GstVideoOverlayRectangle *rect;
   GstVideoMeta *overlay_meta;
@@ -498,14 +554,21 @@ gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay)
 
   overlay_meta = gst_buffer_get_video_meta (overlay->pixels);
 
-  x = overlay->offset_x < 0 ?
-      video_width + overlay->offset_x - overlay_meta->width +
-      (overlay->relative_x * overlay_meta->width) :
-      overlay->offset_x + (overlay->relative_x * overlay_meta->width);
-  y = overlay->offset_y < 0 ?
-      video_height + overlay->offset_y - overlay_meta->height +
-      (overlay->relative_y * overlay_meta->height) :
-      overlay->offset_y + (overlay->relative_y * overlay_meta->height);
+  positioning_mode = overlay->positioning_mode;
+
+  if (positioning_mode == GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE) {
+    x = overlay->offset_x + (overlay->relative_x * overlay_meta->width);
+    y = overlay->offset_y + (overlay->relative_y * overlay_meta->height);
+  } else {
+    x = overlay->offset_x < 0 ?
+        video_width + overlay->offset_x - overlay_meta->width +
+        (overlay->relative_x * overlay_meta->width) :
+        overlay->offset_x + (overlay->relative_x * overlay_meta->width);
+    y = overlay->offset_y < 0 ?
+        video_height + overlay->offset_y - overlay_meta->height +
+        (overlay->relative_y * overlay_meta->height) :
+        overlay->offset_y + (overlay->relative_y * overlay_meta->height);
+  }
 
   width = overlay->overlay_width;
   if (width == 0)
index 2b7ab1eabc9e95ed1cf121d36af77779be9d2104..36b919b2863d7d1e8792d2c2d62a2d2c47186725 100644 (file)
@@ -37,6 +37,11 @@ G_BEGIN_DECLS
 typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay;
 typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass;
 
+typedef enum {
+  GST_GDK_PIXBUF_POSITIONING_PIXELS_RELATIVE_TO_EDGES,
+  GST_GDK_PIXBUF_POSITIONING_PIXELS_ABSOLUTE
+} GstGdkPixbufPositioningMode;
+
 /**
  * GstGdkPixbufOverlay:
  *
@@ -58,6 +63,8 @@ struct _GstGdkPixbufOverlay
   gdouble                      relative_x;
   gdouble                      relative_y;
 
+  GstGdkPixbufPositioningMode  positioning_mode;
+
   gint                         overlay_width;
   gint                         overlay_height;