glvideomixer: implement glBlendFunc and glBlendEquation
authorMatthew Waters <matthew@centricular.com>
Tue, 12 Jan 2016 07:21:50 +0000 (18:21 +1100)
committerMatthew Waters <matthew@centricular.com>
Wed, 13 Jan 2016 01:00:03 +0000 (12:00 +1100)
Allows more blending options than just A over B

e.g. frame comparisons are now possible.
  glvideomixer name=m
    sink_0::zorder=0
    sink_1::zorder=1
    sink_1::blend-equation-rgb={subtract,reverse-subtract}
    sink_1::blend-function-src-rgb=src-color
    sink_1::blend-function-dst-rgb=dst-color
  ! glimagesinkelement
  videotestsrc pattern=checkers-4 ! m.sink_0
  videotestsrc pattern=checkers-8 ! m.sink_1

ext/gl/gstglvideomixer.c
ext/gl/gstglvideomixer.h

index 9376793be2f2a73f6244051b15b2eb95dda5701c..f372f0cfb18d48eaa22aa52dc5de8b5802e51db5 100644 (file)
@@ -71,6 +71,72 @@ gst_gl_video_mixer_background_get_type (void)
   return mixer_background_type;
 }
 
+#define GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION (gst_gl_video_mixer_blend_equation_get_type())
+static GType
+gst_gl_video_mixer_blend_equation_get_type (void)
+{
+  static GType mixer_blend_equation_type = 0;
+
+  static const GEnumValue mixer_blend_equations[] = {
+    {GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD, "Add", "add"},
+    {GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT, "Subtract", "subtract"},
+    {GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT, "Reverse Subtract",
+        "reverse-subtract"},
+    {0, NULL, NULL},
+  };
+
+  if (!mixer_blend_equation_type) {
+    mixer_blend_equation_type =
+        g_enum_register_static ("GstGLVideoMixerBlendEquation",
+        mixer_blend_equations);
+  }
+  return mixer_blend_equation_type;
+}
+
+#define GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION (gst_gl_video_mixer_blend_function_get_type())
+static GType
+gst_gl_video_mixer_blend_function_get_type (void)
+{
+  static GType mixer_blend_function_type = 0;
+
+  static const GEnumValue mixer_blend_funcs[] = {
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO, "Zero", "zero"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE, "One", "one"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR, "Source Color", "src-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR,
+        "One Minus Source Color", "one-minus-src-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR, "Destination Color",
+        "dst-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR,
+        "One Minus Destination Color", "one-minus-dst-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA, "Source Alpha", "src-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA,
+        "One Minus Source Alpha", "one-minus-src-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA, "Destination Alpha",
+        "dst-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA,
+        "One Minus Destination Alpha", "one-minus-dst-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR, "Constant Color",
+        "constant-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR,
+        "One Minus Constant Color", "one-minus-contant-color"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA, "Constant Alpha",
+        "constant-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR,
+        "One Minus Constant Alpha", "one-minus-contant-alpha"},
+    {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE,
+        "Source Alpha Saturate", "src-alpha-saturate"},
+    {0, NULL, NULL},
+  };
+
+  if (!mixer_blend_function_type) {
+    mixer_blend_function_type =
+        g_enum_register_static ("GstGLVideoMixerBlendFunction",
+        mixer_blend_funcs);
+  }
+  return mixer_blend_function_type;
+}
+
 typedef struct _GstGLMixerControlBindingProxy GstGLMixerControlBindingProxy;
 typedef struct _GstGLMixerControlBindingProxyClass
     GstGLMixerControlBindingProxyClass;
@@ -223,6 +289,12 @@ gst_gl_mixer_control_binding_proxy_new (GstObject * object,
 #define DEFAULT_PAD_ALPHA  1.0
 #define DEFAULT_PAD_ZORDER 0
 #define DEFAULT_PAD_IGNORE_EOS FALSE
+#define DEFAULT_PAD_BLEND_EQUATION_RGB GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD
+#define DEFAULT_PAD_BLEND_EQUATION_ALPHA GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD
+#define DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA
+#define DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA
+#define DEFAULT_PAD_BLEND_FUNCTION_DST_RGB GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA
+#define DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA
 
 enum
 {
@@ -232,6 +304,16 @@ enum
   PROP_INPUT_WIDTH,
   PROP_INPUT_HEIGHT,
   PROP_INPUT_ALPHA,
+  PROP_INPUT_BLEND_EQUATION_RGB,
+  PROP_INPUT_BLEND_EQUATION_ALPHA,
+  PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
+  PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
+  PROP_INPUT_BLEND_FUNCTION_DST_RGB,
+  PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
+  PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_RED,
+  PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
+  PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
+  PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
   PROP_INPUT_ZORDER,
   PROP_INPUT_IGNORE_EOS,
 };
@@ -299,6 +381,71 @@ gst_gl_video_mixer_input_class_init (GstGLVideoMixerInputClass * klass)
       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
           DEFAULT_PAD_ALPHA,
           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_EQUATION_RGB,
+      g_param_spec_enum ("blend-equation-rgb", "Blend Equation RGB",
+          "Blend Equation for RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
+          DEFAULT_PAD_BLEND_EQUATION_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_EQUATION_ALPHA,
+      g_param_spec_enum ("blend-equation-alpha", "Blend Equation Alpha",
+          "Blend Equation for Alpha", GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
+          DEFAULT_PAD_BLEND_EQUATION_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
+      g_param_spec_enum ("blend-function-src-rgb", "Blend Function Source RGB",
+          "Blend Function for Source RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
+      g_param_spec_enum ("blend-function-src-alpha",
+          "Blend Function Source Alpha", "Blend Function for Source Alpha",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_DST_RGB,
+      g_param_spec_enum ("blend-function-dst-rgb",
+          "Blend Function Destination RGB",
+          "Blend Function for Destination RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_DST_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
+      g_param_spec_enum ("blend-function-dst-alpha",
+          "Blend Function Destination Alpha",
+          "Blend Function for Destiniation Alpha",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_RED,
+      g_param_spec_double ("blend-constant-color-red",
+          "Blend Constant Color Red", "Blend Constant Color Red", 0.0, 1.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
+      g_param_spec_double ("blend-constant-color-green",
+          "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
+      g_param_spec_double ("blend-constant-color-blue",
+          "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
+      g_param_spec_double ("blend-constant-color-alpha",
+          "Blend Constant Color Alpha", "Blend Constant Color Alpha", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -336,15 +483,25 @@ _create_video_mixer_input (GstGLMixerBin * self, GstPad * mixer_pad)
   }
 #define ADD_PROXY_CONTROL_BINDING(prop)                                \
   cb = gst_gl_mixer_control_binding_proxy_new (GST_OBJECT (mixer_pad), \
-      G_STRINGIFY (prop), GST_OBJECT (input), G_STRINGIFY (prop));     \
+      prop, GST_OBJECT (input), prop);     \
   gst_object_add_control_binding (GST_OBJECT (mixer_pad), cb)
 
-  ADD_PROXY_CONTROL_BINDING (zorder);
-  ADD_PROXY_CONTROL_BINDING (xpos);
-  ADD_PROXY_CONTROL_BINDING (ypos);
-  ADD_PROXY_CONTROL_BINDING (width);
-  ADD_PROXY_CONTROL_BINDING (height);
-  ADD_PROXY_CONTROL_BINDING (alpha);
+  ADD_PROXY_CONTROL_BINDING ("zorder");
+  ADD_PROXY_CONTROL_BINDING ("xpos");
+  ADD_PROXY_CONTROL_BINDING ("ypos");
+  ADD_PROXY_CONTROL_BINDING ("width");
+  ADD_PROXY_CONTROL_BINDING ("height");
+  ADD_PROXY_CONTROL_BINDING ("alpha");
+  ADD_PROXY_CONTROL_BINDING ("blend-equation-rgb");
+  ADD_PROXY_CONTROL_BINDING ("blend-equation-alpha");
+  ADD_PROXY_CONTROL_BINDING ("blend-function-src-rgb");
+  ADD_PROXY_CONTROL_BINDING ("blend-function-src-alpha");
+  ADD_PROXY_CONTROL_BINDING ("blend-function-dst-rgb");
+  ADD_PROXY_CONTROL_BINDING ("blend-function-dst-alpha");
+  ADD_PROXY_CONTROL_BINDING ("blend-constant-color-red");
+  ADD_PROXY_CONTROL_BINDING ("blend-constant-color-green");
+  ADD_PROXY_CONTROL_BINDING ("blend-constant-color-blue");
+  ADD_PROXY_CONTROL_BINDING ("blend-constant-color-alpha");
 
 #undef ADD_PROXY_CONTROL_BINDING
 
@@ -534,6 +691,17 @@ struct _GstGLVideoMixerPad
   gint width, height;
   gdouble alpha;
 
+  GstGLVideoMixerBlendEquation blend_equation_rgb;
+  GstGLVideoMixerBlendEquation blend_equation_alpha;
+  GstGLVideoMixerBlendFunction blend_function_src_rgb;
+  GstGLVideoMixerBlendFunction blend_function_src_alpha;
+  GstGLVideoMixerBlendFunction blend_function_dst_rgb;
+  GstGLVideoMixerBlendFunction blend_function_dst_alpha;
+  gdouble blend_constant_color_red;
+  gdouble blend_constant_color_green;
+  gdouble blend_constant_color_blue;
+  gdouble blend_constant_color_alpha;
+
   gboolean geometry_change;
   GLuint vertex_buffer;
 };
@@ -559,13 +727,29 @@ enum
   PROP_PAD_YPOS,
   PROP_PAD_WIDTH,
   PROP_PAD_HEIGHT,
-  PROP_PAD_ALPHA
+  PROP_PAD_ALPHA,
+  PROP_PAD_BLEND_EQUATION_RGB,
+  PROP_PAD_BLEND_EQUATION_ALPHA,
+  PROP_PAD_BLEND_FUNCTION_SRC_RGB,
+  PROP_PAD_BLEND_FUNCTION_SRC_ALPHA,
+  PROP_PAD_BLEND_FUNCTION_DST_RGB,
+  PROP_PAD_BLEND_FUNCTION_DST_ALPHA,
+  PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED,
+  PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
+  PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
+  PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
 };
 
 static void
 gst_gl_video_mixer_pad_init (GstGLVideoMixerPad * pad)
 {
-  pad->alpha = 1.0;
+  pad->alpha = DEFAULT_PAD_ALPHA;
+  pad->blend_equation_rgb = DEFAULT_PAD_BLEND_EQUATION_RGB;
+  pad->blend_equation_alpha = DEFAULT_PAD_BLEND_EQUATION_ALPHA;
+  pad->blend_function_src_rgb = DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB;
+  pad->blend_function_src_alpha = DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA;
+  pad->blend_function_dst_rgb = DEFAULT_PAD_BLEND_FUNCTION_DST_RGB;
+  pad->blend_function_dst_alpha = DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA;
 }
 
 static void
@@ -596,6 +780,71 @@ gst_gl_video_mixer_pad_class_init (GstGLVideoMixerPadClass * klass)
       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
           DEFAULT_PAD_ALPHA,
           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_EQUATION_RGB,
+      g_param_spec_enum ("blend-equation-rgb", "Blend Equation RGB",
+          "Blend Equation for RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
+          DEFAULT_PAD_BLEND_EQUATION_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_EQUATION_ALPHA,
+      g_param_spec_enum ("blend-equation-alpha", "Blend Equation Alpha",
+          "Blend Equation for Alpha", GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
+          DEFAULT_PAD_BLEND_EQUATION_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
+      g_param_spec_enum ("blend-function-src-rgb", "Blend Function Source RGB",
+          "Blend Function for Source RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
+      g_param_spec_enum ("blend-function-src-alpha",
+          "Blend Function Source Alpha", "Blend Function for Source Alpha",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_DST_RGB,
+      g_param_spec_enum ("blend-function-dst-rgb",
+          "Blend Function Destination RGB",
+          "Blend Function for Destination RGB",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_DST_RGB,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
+      g_param_spec_enum ("blend-function-dst-alpha",
+          "Blend Function Destination Alpha",
+          "Blend Function for Destiniation Alpha",
+          GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
+          DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED,
+      g_param_spec_double ("blend-constant-color-red",
+          "Blend Constant Color Red", "Blend Constant Color Red", 0.0, 1.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
+      g_param_spec_double ("blend-constant-color-green",
+          "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
+      g_param_spec_double ("blend-constant-color-blue",
+          "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
+      g_param_spec_double ("blend-constant-color-alpha",
+          "Blend Constant Color Alpha", "Blend Constant Color Alpha", 0.0, 1.0,
+          0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -620,6 +869,36 @@ gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id,
     case PROP_PAD_ALPHA:
       g_value_set_double (value, pad->alpha);
       break;
+    case PROP_PAD_BLEND_EQUATION_RGB:
+      g_value_set_enum (value, pad->blend_equation_rgb);
+      break;
+    case PROP_PAD_BLEND_EQUATION_ALPHA:
+      g_value_set_enum (value, pad->blend_equation_alpha);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
+      g_value_set_enum (value, pad->blend_function_src_rgb);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
+      g_value_set_enum (value, pad->blend_function_src_alpha);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_DST_RGB:
+      g_value_set_enum (value, pad->blend_function_dst_rgb);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
+      g_value_set_enum (value, pad->blend_function_dst_alpha);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
+      g_value_set_double (value, pad->blend_constant_color_red);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
+      g_value_set_double (value, pad->blend_constant_color_green);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
+      g_value_set_double (value, pad->blend_constant_color_blue);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
+      g_value_set_double (value, pad->blend_constant_color_alpha);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -653,6 +932,36 @@ gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id,
     case PROP_PAD_ALPHA:
       pad->alpha = g_value_get_double (value);
       break;
+    case PROP_PAD_BLEND_EQUATION_RGB:
+      pad->blend_equation_rgb = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_EQUATION_ALPHA:
+      pad->blend_equation_alpha = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
+      pad->blend_function_src_rgb = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
+      pad->blend_function_src_alpha = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_DST_RGB:
+      pad->blend_function_dst_rgb = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
+      pad->blend_function_dst_alpha = g_value_get_enum (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
+      pad->blend_constant_color_red = g_value_get_double (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
+      pad->blend_constant_color_green = g_value_get_double (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
+      pad->blend_constant_color_blue = g_value_get_double (value);
+      break;
+    case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
+      pad->blend_constant_color_alpha = g_value_get_double (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1017,6 +1326,123 @@ _draw_background (GstGLVideoMixer * video_mixer)
   return TRUE;
 }
 
+static guint
+_blend_equation_to_gl (GstGLVideoMixerBlendEquation equation)
+{
+  switch (equation) {
+    case GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD:
+      return GL_FUNC_ADD;
+    case GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT:
+      return GL_FUNC_SUBTRACT;
+    case GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT:
+      return GL_FUNC_REVERSE_SUBTRACT;
+    default:
+      g_assert_not_reached ();
+      return 0;
+  }
+}
+
+static guint
+_blend_function_to_gl (GstGLVideoMixerBlendFunction equation)
+{
+  switch (equation) {
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO:
+      return GL_ZERO;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE:
+      return GL_ONE;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR:
+      return GL_SRC_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR:
+      return GL_ONE_MINUS_SRC_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR:
+      return GL_DST_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR:
+      return GL_ONE_MINUS_DST_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA:
+      return GL_SRC_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA:
+      return GL_ONE_MINUS_SRC_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA:
+      return GL_DST_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA:
+      return GL_ONE_MINUS_DST_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR:
+      return GL_CONSTANT_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR:
+      return GL_ONE_MINUS_CONSTANT_COLOR;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA:
+      return GL_CONSTANT_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_ALPHA:
+      return GL_ONE_MINUS_CONSTANT_ALPHA;
+    case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE:
+      return GL_SRC_ALPHA_SATURATE;
+    default:
+      g_assert_not_reached ();
+      return 0;
+  }
+}
+
+static gboolean
+_set_blend_state (GstGLVideoMixer * video_mixer, GstGLVideoMixerPad * mix_pad)
+{
+  const GstGLFuncs *gl = GST_GL_BASE_MIXER (video_mixer)->context->gl_vtable;
+  gboolean require_separate = FALSE;
+  guint gl_func_src_rgb, gl_func_src_alpha, gl_func_dst_rgb, gl_func_dst_alpha;
+  guint gl_equation_rgb, gl_equation_alpha;
+
+  require_separate =
+      mix_pad->blend_equation_rgb != mix_pad->blend_equation_alpha
+      || mix_pad->blend_function_src_rgb != mix_pad->blend_function_src_alpha
+      || mix_pad->blend_function_dst_rgb != mix_pad->blend_function_dst_alpha;
+
+  if (require_separate && (!gl->BlendFuncSeparate
+          || !gl->BlendEquationSeparate)) {
+    GST_ERROR_OBJECT (mix_pad,
+        "separated blend equations/functions requested however "
+        "glBlendFuncSeparate or glBlendEquationSeparate not available");
+    return FALSE;
+  }
+
+  if (mix_pad->blend_function_dst_rgb ==
+      GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE) {
+    GST_ERROR_OBJECT (mix_pad,
+        "Destination RGB blend function cannot be \'SRC_ALPHA_SATURATE\'");
+    return FALSE;
+  }
+
+  if (mix_pad->blend_function_dst_alpha ==
+      GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE) {
+    GST_ERROR_OBJECT (mix_pad,
+        "Destination alpha blend function cannot be \'SRC_ALPHA_SATURATE\'");
+    return FALSE;
+  }
+
+  gl_equation_rgb = _blend_equation_to_gl (mix_pad->blend_equation_rgb);
+  gl_equation_alpha = _blend_equation_to_gl (mix_pad->blend_equation_alpha);
+
+  gl_func_src_rgb = _blend_function_to_gl (mix_pad->blend_function_src_rgb);
+  gl_func_src_alpha = _blend_function_to_gl (mix_pad->blend_function_src_alpha);
+  gl_func_dst_rgb = _blend_function_to_gl (mix_pad->blend_function_dst_rgb);
+  gl_func_dst_alpha = _blend_function_to_gl (mix_pad->blend_function_dst_alpha);
+
+  if (gl->BlendEquationSeparate)
+    gl->BlendEquationSeparate (gl_equation_rgb, gl_equation_alpha);
+  else
+    gl->BlendEquation (gl_equation_rgb);
+
+  if (gl->BlendFuncSeparate)
+    gl->BlendFuncSeparate (gl_func_src_rgb, gl_func_dst_rgb, gl_func_src_alpha,
+        gl_func_dst_alpha);
+  else
+    gl->BlendFunc (gl_func_src_rgb, gl_func_dst_rgb);
+
+  gl->BlendColor (mix_pad->blend_constant_color_red,
+      mix_pad->blend_constant_color_green, mix_pad->blend_constant_color_blue,
+      mix_pad->blend_constant_color_alpha);
+
+  return TRUE;
+}
+
 /* opengl scene, params: input texture (not the output mixer->texture) */
 static void
 gst_gl_video_mixer_callback (gpointer stuff)
@@ -1094,6 +1520,11 @@ gst_gl_video_mixer_callback (gpointer stuff)
       continue;
     }
 
+    if (!_set_blend_state (video_mixer, pad)) {
+      GST_FIXME_OBJECT (pad, "skipping due to incorrect blend parameters");
+      continue;
+    }
+
     in_tex = frame->texture;
 
     _init_vbo_indices (video_mixer);
@@ -1135,9 +1566,6 @@ gst_gl_video_mixer_callback (gpointer stuff)
     }
     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices);
 
-    gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    gl->BlendEquation (GL_FUNC_ADD);
-
     gl->ActiveTexture (GL_TEXTURE0);
     gl->BindTexture (GL_TEXTURE_2D, in_tex);
     gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0);
index 0d0252b56f34d4698331ec563aa0f552ae4ae00a..86c0506d25ab8af30441656101bdd2863412bd65 100644 (file)
@@ -53,6 +53,66 @@ typedef enum
 }
 GstGLVideoMixerBackground;
 
+/**
+ * GstGLVideoMixerBlendEquation:
+ * @GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD: Add the two results.
+ * @GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT: Subtract component-wise the destination from the source (S - D).
+ * @GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT: Subtract component-wise the source from the destination (D - S).
+ *
+ * The blending equation to use.  See the opengl specificition for
+ * glBlendEquationSeparate
+ */
+typedef enum
+{
+  GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD,
+  GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT,
+  GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT,
+}
+GstGLVideoMixerBlendEquation;
+
+/**
+ * GstGLVideoMixerBlendFunction:
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO: All components are zero
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE: All components are one
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR: Use the source color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR: One minus the source color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR: Use the destination color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR: One minus the destination color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA: All components are the source alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA: All components are one minus the source alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA: All components are the destination alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA: All components are one minus the destination alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR: Use the constant color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR: Use one minus the constant color/alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA: All components are the constant alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR: All components are one minus the constant alpha
+ * @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE: All color components
+ *     are the minimum of source alpha and one minus the destination alpha.
+ *     Alpha is equal to one.
+ *
+ * The blending function to use.  See the opengl specificition for
+ * glBlendFuncSeparate
+ */
+typedef enum
+{
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_ALPHA,
+  GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE,
+}
+GstGLVideoMixerBlendFunction;
+
 struct _GstGLVideoMixer
 {
     GstGLMixer mixer;