diff --git a/gst-libs/gst/video/video-blend.c b/gst-libs/gst/video/video-blend.c
index 9231464..89fd9ca 100644
--- a/gst-libs/gst/video/video-blend.c
+++ b/gst-libs/gst/video/video-blend.c
@@ -1333,12 +1333,15 @@ video_blend_scale_linear_RGBA (GstBlendVideoFormatInfo * src,
  * @dest
  * @x: The x offset in pixel where the @src image should be blended
  * @y: the y offset in pixel where the @src image should be blended
+ * @global_alpha: the global_alpha each per-pixel alpha value is multiplied
+ *                with
  *
  * Lets you blend the @src image into the @dest image
  */
 gboolean
 video_blend (GstBlendVideoFormatInfo * dest,
-    GstBlendVideoFormatInfo * src, guint x, guint y)
+    GstBlendVideoFormatInfo * src, guint x, guint y,
+    gfloat global_alpha)
 {
   guint i, j;
   guint8 alpha;
@@ -1349,6 +1352,7 @@ video_blend (GstBlendVideoFormatInfo * dest,
 
   g_return_val_if_fail (dest, FALSE);
   g_return_val_if_fail (src, FALSE);
+  g_return_val_if_fail (global_alpha >= 0 && global_alpha <= 1, FALSE);
 
   /* we do no support writing to premultiplied alpha, though that should
      just be a matter of adding blenders below (BLEND01 and BLEND11) */
@@ -1414,7 +1418,7 @@ video_blend (GstBlendVideoFormatInfo * dest,
 #define BLENDLOOP(blender)                                                        \
   do {                                                                            \
     for (j = 0; j < src->width * 4; j += 4) {                                     \
-      alpha = tmpsrcline[j];                                                      \
+      alpha = (guint8) tmpsrcline[j] * global_alpha;                              \
                                                                                   \
       blender (tmpdestline[j + 1], alpha, tmpsrcline[j + 1], tmpdestline[j + 1]); \
       blender (tmpdestline[j + 2], alpha, tmpsrcline[j + 2], tmpdestline[j + 2]); \
diff --git a/gst-libs/gst/video/video-blend.h b/gst-libs/gst/video/video-blend.h
index f3673a6..7e4c50f 100644
--- a/gst-libs/gst/video/video-blend.h
+++ b/gst-libs/gst/video/video-blend.h
@@ -71,6 +71,7 @@ void       video_blend_scale_linear_RGBA  (GstBlendVideoFormatInfo * src,
 
 gboolean   video_blend                    (GstBlendVideoFormatInfo * dest,
                                            GstBlendVideoFormatInfo * src,
-                                           guint x, guint y);
+                                           guint x, guint y,
+                                           gfloat global_alpha);
 
 #endif
diff --git a/gst-libs/gst/video/video-overlay-composition.c b/gst-libs/gst/video/video-overlay-composition.c
index 4633b6b..3ba49c5 100644
--- a/gst-libs/gst/video/video-overlay-composition.c
+++ b/gst-libs/gst/video/video-overlay-composition.c
@@ -69,6 +69,7 @@
 
 #include "video-overlay-composition.h"
 #include "video-blend.h"
+#include <string.h>
 
 struct _GstVideoOverlayComposition
 {
@@ -134,6 +135,19 @@ struct _GstVideoOverlayRectangle
    * rectangles have expired. */
   guint seq_num;
 
+  /* global alpha: global alpha value of the rectangle. Each each per-pixel
+   * alpha value of image-data will be multiplied with the global alpha value
+   * during blending.
+   * Can be used for efficient fading in/out of overlay rectangles.
+   * GstElements that render OverlayCompositions and don't support global alpha
+   * should simply ignore it.*/
+  gfloat global_alpha;
+
+  /* track alpha-values already applied: */
+  gfloat applied_global_alpha;
+  /* store initial per-pixel alpha values: */
+  guint8 *initial_alpha;
+
   /* FIXME: we may also need a (private) way to cache converted/scaled
    * pixel blobs */
 #if !GLIB_CHECK_VERSION (2, 31, 0)
@@ -530,7 +544,8 @@ gst_video_overlay_composition_blend (GstVideoOverlayComposition * comp,
           rect->render_width);
     }
 
-    ret = video_blend (&video_info, &rectangle_info, rect->x, rect->y);
+    ret = video_blend (&video_info, &rectangle_info, rect->x, rect->y,
+            rect->global_alpha);
     if (!ret) {
       GST_WARNING ("Could not blend overlay rectangle onto video buffer");
     }
@@ -683,6 +698,9 @@ gst_video_overlay_rectangle_finalize (GstMiniObject * mini_obj)
     rect->scaled_rectangles =
         g_list_delete_link (rect->scaled_rectangles, rect->scaled_rectangles);
   }
+
+  if (rect->initial_alpha)
+      g_free(rect->initial_alpha);
 #if !GLIB_CHECK_VERSION (2, 31, 0)
   g_static_mutex_free (&rect->lock);
 #else
@@ -714,7 +732,8 @@ static inline gboolean
 gst_video_overlay_rectangle_check_flags (GstVideoOverlayFormatFlags flags)
 {
   /* Check flags only contains flags we know about */
-  return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) == 0;
+  return (flags & ~(GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA |
+                    GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)) == 0;
 }
 
 static gboolean
@@ -790,13 +809,18 @@ gst_video_overlay_rectangle_new_argb (GstBuffer * pixels,
   rect->render_width = render_width;
   rect->render_height = render_height;
 
+  rect->global_alpha = 1.0;
+  rect->applied_global_alpha = 1.0;
+  rect->initial_alpha = NULL;
+
   rect->flags = flags;
 
   rect->seq_num = gst_video_overlay_get_seqnum ();
 
   GST_LOG ("new rectangle %p: %ux%u => %ux%u @ %u,%u, seq_num %u, format %u, "
-      "flags %x, pixels %p", rect, width, height, render_width, render_height,
-      render_x, render_y, rect->seq_num, rect->format, rect->flags, pixels);
+      "flags %x, pixels %p, global_alpha=%f", rect, width, height, render_width,
+      render_height, render_x, render_y, rect->seq_num, rect->format, rect->flags,
+      pixels, rect->global_alpha);
 
   return rect;
 }
@@ -873,13 +897,17 @@ static void
 gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
 {
   int i, j;
+  guint8 alpha_channel = 3; /* derive from video-format? */
+  guint8 c1 = (alpha_channel + 1) % MAX_VIDEO_PLANES;
+  guint8 c2 = (alpha_channel + 2) % MAX_VIDEO_PLANES;
+  guint8 c3 = (alpha_channel + 3) % MAX_VIDEO_PLANES;
   for (j = 0; j < info->height; ++j) {
     guint8 *line = info->pixels + info->stride[0] * j;
     for (i = 0; i < info->width; ++i) {
-      int a = line[0];
-      line[1] = line[1] * a / 255;
-      line[2] = line[2] * a / 255;
-      line[3] = line[3] * a / 255;
+      int a = line[alpha_channel];
+      line[c1] = line[c1] * a / 255;
+      line[c2] = line[c2] * a / 255;
+      line[c3] = line[c3] * a / 255;
       line += 4;
     }
   }
@@ -889,20 +917,90 @@ static void
 gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
 {
   int i, j;
+  guint8 alpha_channel = 3; /* derive from video-format? */
+  guint8 c1 = (alpha_channel + 1) % MAX_VIDEO_PLANES;
+  guint8 c2 = (alpha_channel + 2) % MAX_VIDEO_PLANES;
+  guint8 c3 = (alpha_channel + 3) % MAX_VIDEO_PLANES;
   for (j = 0; j < info->height; ++j) {
     guint8 *line = info->pixels + info->stride[0] * j;
     for (i = 0; i < info->width; ++i) {
-      int a = line[0];
+      int a = line[alpha_channel];
       if (a) {
-        line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
-        line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
-        line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
+        line[c1] = MIN ((line[c1] * 255 + a / 2) / a, 255);
+        line[c2] = MIN ((line[c2] * 255 + a / 2) / a, 255);
+        line[c3] = MIN ((line[c3] * 255 + a / 2) / a, 255);
       }
       line += 4;
     }
   }
 }
 
+
+static gboolean
+gst_video_overlay_rectangle_extract_alpha(GstVideoOverlayRectangle *rect)
+{
+    int bpp = 4;  /* derive from video-format? */
+    guint8 alpha_channel = 3; /* derive from video-format? */
+    guint8 *src, *dst;
+    int offset = 0;
+    int alpha_size = rect->stride * rect->height / bpp;
+
+    if (rect->initial_alpha) {
+        g_free(rect->initial_alpha);
+        rect->initial_alpha = NULL;
+    }
+
+    rect->initial_alpha = g_malloc(alpha_size);
+    if (!rect->initial_alpha)
+        return FALSE;
+
+    src = GST_BUFFER_DATA (rect->pixels);
+    dst = rect->initial_alpha;
+    while (offset < alpha_size) {
+        dst[offset] = src[offset * 4 + alpha_channel];
+        ++offset;
+    }
+    return TRUE;
+}
+
+
+static gboolean
+gst_video_overlay_rectangle_apply_global_alpha(GstVideoOverlayRectangle *rect)
+{
+    guint8 *src, *dst;
+    guint offset = 0;
+    guint8 alpha_channel = 3; /* derive from video-format? */
+    guint8 c1 = (alpha_channel + 1) % MAX_VIDEO_PLANES;
+    guint8 c2 = (alpha_channel + 2) % MAX_VIDEO_PLANES;
+    guint8 c3 = (alpha_channel + 3) % MAX_VIDEO_PLANES;
+    guint8 bpp = 4; /* derive from video-format? */
+
+    g_return_val_if_fail(!(rect->applied_global_alpha != 1.0 && rect->initial_alpha == NULL), FALSE);
+
+    if (rect->global_alpha == rect->applied_global_alpha)
+        return TRUE;
+
+    if (rect->initial_alpha == NULL &&
+        !gst_video_overlay_rectangle_extract_alpha(rect))
+    return FALSE;
+
+    src = rect->initial_alpha;
+    dst = GST_BUFFER_DATA (rect->pixels);
+    while (offset < (rect->height * rect->stride / bpp)) {
+        guint doff = offset * 4;
+        guint8 na = (guint8) src[offset] * rect->global_alpha;
+        if (!!(rect->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)) {
+            dst[doff + c1] = (guint8) ((double) (dst[doff + c1] * 255) / (double) dst[doff + alpha_channel] ) * na / 255;
+            dst[doff + c2] = (guint8) ((double) (dst[doff + c2] * 255) / (double) dst[doff + alpha_channel] ) * na / 255;
+            dst[doff + c3] = (guint8) ((double) (dst[doff + c3] * 255) / (double) dst[doff + alpha_channel] ) * na / 255;
+        }
+        dst[doff + alpha_channel] = na;
+        ++offset;
+    }
+    rect->applied_global_alpha = rect->global_alpha;
+    return TRUE;
+}
+
 static GstBuffer *
 gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
     rectangle, guint * stride, GstVideoOverlayFormatFlags flags,
@@ -910,20 +1008,26 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 {
   GstVideoOverlayRectangle *scaled_rect = NULL;
   GstBlendVideoFormatInfo info;
+  GstVideoOverlayFormatFlags new_flags = rectangle->flags;
   GstBuffer *buf;
   GList *l;
   guint wanted_width = unscaled ? rectangle->width : rectangle->render_width;
   guint wanted_height = unscaled ? rectangle->height : rectangle->render_height;
+  gboolean apply_global_alpha;
 
   g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), NULL);
   g_return_val_if_fail (stride != NULL, NULL);
   g_return_val_if_fail (gst_video_overlay_rectangle_check_flags (flags), NULL);
 
+  apply_global_alpha = (!!(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA) &&
+                        !(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA));
+
   /* This assumes we don't need to adjust the format */
   if (wanted_width == rectangle->width &&
       wanted_height == rectangle->height &&
       gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
-          flags)) {
+          flags) &&
+      (!apply_global_alpha || rectangle->applied_global_alpha == rectangle->global_alpha)) {
     *stride = rectangle->stride;
     return rectangle->pixels;
   }
@@ -935,7 +1039,7 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 
     if (r->width == wanted_width &&
         r->height == wanted_height &&
-        gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
+        gst_video_overlay_rectangle_is_same_alpha_type (r->flags,
             flags)) {
       /* we'll keep these rectangles around until finalize, so it's ok not
        * to take our own ref here */
@@ -948,20 +1052,28 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
   if (scaled_rect != NULL)
     goto done;
 
-  /* not cached yet, do the scaling and put the result into our cache */
+  /* not cached yet, do the preprocessing and put the result into our cache */
   video_blend_format_info_init (&info, GST_BUFFER_DATA (rectangle->pixels),
       rectangle->height, rectangle->width, rectangle->format,
       !!(rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA));
 
   if (wanted_width != rectangle->width || wanted_height != rectangle->height) {
+    /* we could check the cache for a scaled rect with global_alpha == 1 here*/
     video_blend_scale_linear_RGBA (&info, wanted_height, wanted_width);
+  } else {
+      /* need to clone rectangles pixel-data and update info */
+      guint8 *new_pixels = g_malloc (info.size);
+      memcpy(new_pixels, info.pixels, info.size);
+      info.pixels = new_pixels;
   }
 
   if (!gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags, flags)) {
     if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
       gst_video_overlay_rectangle_unpremultiply (&info);
+      new_flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
     } else {
       gst_video_overlay_rectangle_premultiply (&info);
+      new_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
     }
   }
 
@@ -972,8 +1084,9 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 
   scaled_rect = gst_video_overlay_rectangle_new_argb (buf,
       wanted_width, wanted_height, info.stride[0],
-      0, 0, wanted_width, wanted_height, rectangle->flags);
-
+      0, 0, wanted_width, wanted_height, new_flags);
+  if (rectangle->global_alpha != 1.0)
+      gst_video_overlay_rectangle_set_global_alpha (scaled_rect, rectangle->global_alpha);
   gst_buffer_unref (buf);
 
   GST_RECTANGLE_LOCK (rectangle);
@@ -982,17 +1095,28 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
   GST_RECTANGLE_UNLOCK (rectangle);
 
 done:
+  if (apply_global_alpha && scaled_rect->applied_global_alpha != rectangle->global_alpha)
+  {
+      gst_video_overlay_rectangle_set_global_alpha(scaled_rect, rectangle->global_alpha);
+      if (!gst_video_overlay_rectangle_apply_global_alpha(scaled_rect))
+          return NULL;  /* return original data here? */
+  }
 
   *stride = scaled_rect->stride;
   return scaled_rect->pixels;
 }
 
+
 /**
  * gst_video_overlay_rectangle_get_pixels_argb:
  * @rectangle: a #GstVideoOverlayRectangle
  * @stride: (out) (allow-none): address of guint variable where to store the
  *    row stride of the ARGB pixel data in the buffer
  * @flags: flags
+ *    If a global_alpha value != 1 is set for the rectangle, the caller
+ *    should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
+ *    if he wants to apply global-alpha himself. If the flag is not set
+ *    global_alpha is applied internally before returning the pixel-data.
  *
  * Returns: (transfer none): a #GstBuffer holding the ARGB pixel data with
  *    row stride @stride and width and height of the render dimensions as per
@@ -1019,7 +1143,11 @@ gst_video_overlay_rectangle_get_pixels_argb (GstVideoOverlayRectangle *
  *    rectangle in pixels
  * @stride: (out): address of guint variable where to store the row
  *    stride of the ARGB pixel data in the buffer
- * @flags: flags
+ * @flags: flags.
+ *    If a global_alpha value != 1 is set for the rectangle, the caller
+ *    should set the #GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA flag
+ *    if he wants to apply global-alpha himself. If the flag is not set
+ *    global_alpha is applied internally before returning the pixel-data.
  *
  * Retrieves the pixel data as it is. This is useful if the caller can
  * do the scaling itself when handling the overlaying. The rectangle will
@@ -1072,6 +1200,58 @@ gst_video_overlay_rectangle_get_flags (GstVideoOverlayRectangle * rectangle)
 }
 
 /**
+ * gst_video_overlay_rectangle_get_global_alpha:
+ * @rectangle: a #GstVideoOverlayRectangle
+ *
+ * Retrieves the global-alpha value associated with a #GstVideoOverlayRectangle.
+ *
+ * Returns: the global-alpha value associated with the rectangle.
+ *
+ * Since: 0.10.37
+ */
+gfloat
+gst_video_overlay_rectangle_get_global_alpha (GstVideoOverlayRectangle * rectangle)
+{
+  g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle), -1);
+
+  return rectangle->global_alpha;
+}
+
+/**
+ * gst_video_overlay_rectangle_set_global_alpha:
+ * @rectangle: a #GstVideoOverlayRectangle
+ *
+ * Sets the global alpha value associated with a #GstVideoOverlayRectangle. Per-
+ * pixel alpha values are multiplied with this value. Valid
+ * values: 0 <= global_alpha <= 1; 1 to deactivate.
+ *
+ # @rectangle must be writable, meaning its refcount must be 1. You can
+ * make the rectangles inside a #GstVideoOverlayComposition writable using
+ * gst_video_overlay_composition_make_writable() or
+ * gst_video_overlay_composition_copy().
+ *
+ * Since: 0.10.37
+ */
+void
+gst_video_overlay_rectangle_set_global_alpha (GstVideoOverlayRectangle * rectangle,
+        gfloat global_alpha)
+{
+  g_return_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rectangle));
+  g_return_if_fail (global_alpha >= 0 && global_alpha <=1);
+
+  if (rectangle->global_alpha != global_alpha) {
+      rectangle->global_alpha = global_alpha;
+      if (global_alpha != 1)
+          rectangle->flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
+      else
+          rectangle->flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
+      /* update seq_num automatically to signal the consumer, that data has changed
+       * FIXME: really do this automatically? */
+      rectangle->seq_num = gst_video_overlay_get_seqnum ();
+  }
+}
+
+/**
  * gst_video_overlay_rectangle_copy:
  * @rectangle: (transfer none): a #GstVideoOverlayRectangle to copy
  *
@@ -1096,6 +1276,8 @@ gst_video_overlay_rectangle_copy (GstVideoOverlayRectangle * rectangle)
       rectangle->width, rectangle->height, rectangle->stride,
       rectangle->x, rectangle->y,
       rectangle->render_width, rectangle->render_height, rectangle->flags);
+  if (rectangle->global_alpha != 1)
+      gst_video_overlay_rectangle_set_global_alpha (copy, rectangle->global_alpha);
 
   return copy;
 }
diff --git a/gst-libs/gst/video/video-overlay-composition.h b/gst-libs/gst/video/video-overlay-composition.h
index b91404b..65538e4 100644
--- a/gst-libs/gst/video/video-overlay-composition.h
+++ b/gst-libs/gst/video/video-overlay-composition.h
@@ -96,6 +96,7 @@ gst_video_overlay_rectangle_unref (GstVideoOverlayRectangle * comp)
  * GstVideoOverlayFormatFlags:
  * @GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE: no flags
  * @GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA: RGB are premultiplied by A/255. Since: 0.10.37
+ * @GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA: a global-alpha value != 1 is set. Since: 0.10.37
  *
  * Overlay format flags.
  *
@@ -103,7 +104,8 @@ gst_video_overlay_rectangle_unref (GstVideoOverlayRectangle * comp)
  */
 typedef enum {
   GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE = 0,
-  GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA = 1
+  GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA = 1,
+  GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA = 2
 } GstVideoOverlayFormatFlags;
 
 GType                        gst_video_overlay_rectangle_get_type (void);
@@ -142,6 +144,10 @@ GstBuffer *                  gst_video_overlay_rectangle_get_pixels_unscaled_arg
 
 GstVideoOverlayFormatFlags   gst_video_overlay_rectangle_get_flags                (GstVideoOverlayRectangle  * rectangle);
 
+gfloat                       gst_video_overlay_rectangle_get_global_alpha         (GstVideoOverlayRectangle  * rectangle);
+void                         gst_video_overlay_rectangle_set_global_alpha         (GstVideoOverlayRectangle  * rectangle,
+                                                                                   gfloat                      global_alpha);
+
 /**
  * GstVideoOverlayComposition:
  *
