#endif
#include "gstglvideomixer.h"
+#include "gstglmixerbin.h"
#define GST_CAT_DEFAULT gst_gl_video_mixer_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+#define GST_GL_TYPE_VIDEO_MIXER_BACKGROUND (gst_gl_video_mixer_background_get_type())
+static GType
+gst_gl_video_mixer_background_get_type (void)
+{
+ static GType mixer_background_type = 0;
+
+ static const GEnumValue mixer_background[] = {
+ {GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER, "Checker pattern", "checker"},
+ {GST_GL_VIDEO_MIXER_BACKGROUND_BLACK, "Black", "black"},
+ {GST_GL_VIDEO_MIXER_BACKGROUND_WHITE, "White", "white"},
+ {GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT,
+ "Transparent Background to enable further compositing", "transparent"},
+ {0, NULL, NULL},
+ };
+
+ if (!mixer_background_type) {
+ mixer_background_type =
+ g_enum_register_static ("GstGLVideoMixerBackground", mixer_background);
+ }
+ return mixer_background_type;
+}
+
+#define DEFAULT_PAD_XPOS 0
+#define DEFAULT_PAD_YPOS 0
+#define DEFAULT_PAD_WIDTH 0
+#define DEFAULT_PAD_HEIGHT 0
+#define DEFAULT_PAD_ALPHA 1.0
+#define DEFAULT_PAD_ZORDER 0
+
+enum
+{
+ PROP_INPUT_0,
+ PROP_INPUT_XPOS,
+ PROP_INPUT_YPOS,
+ PROP_INPUT_WIDTH,
+ PROP_INPUT_HEIGHT,
+ PROP_INPUT_ALPHA,
+ PROP_INPUT_ZORDER,
+};
+
+static void gst_gl_video_mixer_input_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_gl_video_mixer_input_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+
+static GstFlowReturn gst_gl_video_mixer_input_chain (GstPad * pad,
+ GstObject * parent, GstBuffer * buffer);
+static GstFlowReturn gst_gl_video_mixer_input_event (GstPad * pad,
+ GstObject * parent, GstEvent * event);
+
+typedef struct _GstGLVideoMixerInput GstGLVideoMixerInput;
+typedef GstGhostPadClass GstGLVideoMixerInputClass;
+
+struct _GstGLVideoMixerInput
+{
+ GstGhostPad parent;
+
+ GstSegment segment;
+
+ GstPad *mixer_pad;
+};
+
+GType gst_gl_video_mixer_input_get_type (void);
+G_DEFINE_TYPE (GstGLVideoMixerInput, gst_gl_video_mixer_input,
+ GST_TYPE_GHOST_PAD);
+
+static void
+gst_gl_video_mixer_input_init (GstGLVideoMixerInput * self)
+{
+ GstPad *pad = GST_PAD (self);
+
+ gst_pad_set_event_function (pad, gst_gl_video_mixer_input_event);
+}
+
+static void
+gst_gl_video_mixer_input_class_init (GstGLVideoMixerInputClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gst_gl_video_mixer_input_set_property;
+ gobject_class->get_property = gst_gl_video_mixer_input_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_INPUT_ZORDER,
+ g_param_spec_uint ("zorder", "Z-Order", "Z Order of the picture",
+ 0, 10000, DEFAULT_PAD_ZORDER,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INPUT_XPOS,
+ g_param_spec_int ("xpos", "X Position", "X Position of the picture",
+ G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INPUT_YPOS,
+ g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
+ G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INPUT_WIDTH,
+ g_param_spec_int ("width", "Width", "Width of the picture",
+ G_MININT, G_MAXINT, DEFAULT_PAD_WIDTH,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INPUT_HEIGHT,
+ g_param_spec_int ("height", "Height", "Height of the picture",
+ G_MININT, G_MAXINT, DEFAULT_PAD_HEIGHT,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_INPUT_ALPHA,
+ 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));
+}
+
+static void
+gst_gl_video_mixer_input_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
+
+ if (self->mixer_pad)
+ g_object_get_property (G_OBJECT (self->mixer_pad), pspec->name, value);
+}
+
+static void
+gst_gl_video_mixer_input_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
+
+ if (self->mixer_pad)
+ g_object_set_property (G_OBJECT (self->mixer_pad), pspec->name, value);
+}
+
+static GstFlowReturn
+gst_gl_video_mixer_input_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer)
+{
+ GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) pad;
+ GstClockTime timestamp, stream_time;
+// gdouble alpha;
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ stream_time =
+ gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
+
+ gst_object_sync_values (GST_OBJECT (self), stream_time);
+#if 0
+ /* FIXME: implement no-upload on alpha = 0 */
+ g_object_get (self, "alpha", &alpha, NULL);
+
+ if (alpha <= 0.0) {
+ GST_DEBUG_OBJECT (self, "dropping buffer %" GST_PTR_FORMAT
+ " due to alpha value %f", buffer, alpha);
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+#endif
+ return gst_proxy_pad_chain_default (pad, parent, buffer);
+}
+
+static GstFlowReturn
+gst_gl_video_mixer_input_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) pad;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ gst_event_copy_segment (event, &self->segment);
+ break;
+ default:
+ break;
+ }
+
+ return gst_pad_event_default (pad, parent, event);
+}
+
+static GstGhostPad *
+_create_video_mixer_input (GstGLMixerBin * self, GstPad * mixer_pad)
+{
+ GstGLVideoMixerInput *input =
+ g_object_new (gst_gl_video_mixer_input_get_type (), "name",
+ GST_OBJECT_NAME (mixer_pad), "direction", GST_PAD_DIRECTION (mixer_pad),
+ NULL);
+
+ if (!gst_ghost_pad_construct (GST_GHOST_PAD (input))) {
+ gst_object_unref (input);
+ return NULL;
+ }
+
+ gst_pad_set_chain_function (GST_PAD (input), gst_gl_video_mixer_input_chain);
+
+ input->mixer_pad = mixer_pad;
+
+ return GST_GHOST_PAD (input);
+}
+
+enum
+{
+ PROP_BIN_0,
+ PROP_BIN_BACKGROUND,
+};
+#define DEFAULT_BACKGROUND GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER
+
+static void gst_gl_video_mixer_bin_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_gl_video_mixer_bin_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+
+typedef GstGLMixerBin GstGLVideoMixerBin;
+typedef GstGLMixerBinClass GstGLVideoMixerBinClass;
+
+G_DEFINE_TYPE (GstGLVideoMixerBin, gst_gl_video_mixer_bin,
+ GST_TYPE_GL_MIXER_BIN);
+
+static void
+gst_gl_video_mixer_bin_init (GstGLVideoMixerBin * self)
+{
+ GstGLMixerBin *mix_bin = GST_GL_MIXER_BIN (self);
+
+ gst_gl_mixer_bin_finish_init_with_element (mix_bin,
+ g_object_new (GST_TYPE_GL_VIDEO_MIXER, NULL));
+}
+
+static void
+gst_gl_video_mixer_bin_class_init (GstGLVideoMixerBinClass * klass)
+{
+ GstGLMixerBinClass *mixer_class = GST_GL_MIXER_BIN_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ mixer_class->create_input_pad = _create_video_mixer_input;
+
+ gobject_class->set_property = gst_gl_video_mixer_bin_set_property;
+ gobject_class->get_property = gst_gl_video_mixer_bin_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_BIN_BACKGROUND,
+ g_param_spec_enum ("background", "Background", "Background type",
+ GST_GL_TYPE_VIDEO_MIXER_BACKGROUND,
+ DEFAULT_BACKGROUND, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_gl_video_mixer_bin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
+
+ if (self->mixer)
+ g_object_get_property (G_OBJECT (self->mixer), pspec->name, value);
+}
+
+static void
+gst_gl_video_mixer_bin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
+
+ if (self->mixer)
+ g_object_set_property (G_OBJECT (self->mixer), pspec->name, value);
+}
+
enum
{
PROP_0,
PROP_BACKGROUND,
};
-#define DEFAULT_BACKGROUND GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element");
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_video_mixer_pad_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstBuffer *gst_gl_video_mixer_pad_upload_buffer (GstGLMixer * mix,
- GstGLMixerFrameData * frame, GstBuffer * buffer);
-#define DEFAULT_PAD_XPOS 0
-#define DEFAULT_PAD_YPOS 0
-#define DEFAULT_PAD_WIDTH 0
-#define DEFAULT_PAD_HEIGHT 0
-#define DEFAULT_PAD_ALPHA 1.0
enum
{
PROP_PAD_0,
gst_gl_video_mixer_pad_class_init (GstGLVideoMixerPadClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
- GstGLMixerPadClass *mix_pad_class = (GstGLMixerPadClass *) klass;
gobject_class->set_property = gst_gl_video_mixer_pad_set_property;
gobject_class->get_property = gst_gl_video_mixer_pad_get_property;
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));
-
- mix_pad_class->upload_buffer = gst_gl_video_mixer_pad_upload_buffer;
}
static void
gst_object_unref (mix);
}
-static GstBuffer *
-gst_gl_video_mixer_pad_upload_buffer (GstGLMixer * mix,
- GstGLMixerFrameData * frame, GstBuffer * buffer)
-{
- GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (frame->pad);
-
- if (pad->alpha > 0.0) {
- return
- GST_GL_MIXER_PAD_CLASS
- (gst_gl_video_mixer_pad_parent_class)->upload_buffer (mix, frame,
- buffer);
- }
-
- return NULL;
-}
-
-#define GST_GL_TYPE_VIDEO_MIXER_BACKGROUND (gst_gl_video_mixer_background_get_type())
-static GType
-gst_gl_video_mixer_background_get_type (void)
-{
- static GType mixer_background_type = 0;
-
- static const GEnumValue mixer_background[] = {
- {GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER, "Checker pattern", "checker"},
- {GST_GL_VIDEO_MIXER_BACKGROUND_BLACK, "Black", "black"},
- {GST_GL_VIDEO_MIXER_BACKGROUND_WHITE, "White", "white"},
- {GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT,
- "Transparent Background to enable further compositing", "transparent"},
- {0, NULL, NULL},
- };
-
- if (!mixer_background_type) {
- mixer_background_type =
- g_enum_register_static ("GstGLVideoMixerBackground", mixer_background);
- }
- return mixer_background_type;
-}
-
static void
gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
{
gst_element_class_set_metadata (element_class, "OpenGL video_mixer",
"Filter/Effect/Video/Compositor", "OpenGL video_mixer",
- "Julien Isorce <julien.isorce@gmail.com>");
+ "Matthew Waters <matthew@centricular.com>");
g_object_class_install_property (gobject_class, PROP_BACKGROUND,
g_param_spec_enum ("background", "Background", "Background type",
}
GST_OBJECT_UNLOCK (vagg);
- ret = gst_gl_mixer_update_caps (GST_GL_MIXER (vagg), caps);
+ ret =
+ GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps
+ (vagg, caps);
for (i = 0; i < gst_caps_get_size (ret); i++) {
GstStructure *s = gst_caps_get_structure (ret, i);