diff --git a/ext/gl/gstglvideomixer.c b/ext/gl/gstglvideomixer.c index b519995cdd..cbba72a5d7 100644 --- a/ext/gl/gstglvideomixer.c +++ b/ext/gl/gstglvideomixer.c @@ -44,16 +44,273 @@ #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"); @@ -178,14 +435,7 @@ static void gst_gl_video_mixer_pad_set_property (GObject * object, 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, @@ -206,7 +456,6 @@ static void 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; @@ -231,8 +480,6 @@ 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)); - - mix_pad_class->upload_buffer = gst_gl_video_mixer_pad_upload_buffer; } static void @@ -298,44 +545,6 @@ gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id, 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) { @@ -352,7 +561,7 @@ 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 "); + "Matthew Waters "); g_object_class_install_property (gobject_class, PROP_BACKGROUND, g_param_spec_enum ("background", "Background", "Background type", @@ -454,7 +663,9 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps) } 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); diff --git a/ext/gl/gstglvideomixer.h b/ext/gl/gstglvideomixer.h index b351888fce..967358baba 100644 --- a/ext/gl/gstglvideomixer.h +++ b/ext/gl/gstglvideomixer.h @@ -73,6 +73,7 @@ struct _GstGLVideoMixerClass }; GType gst_gl_video_mixer_get_type (void); +GType gst_gl_video_mixer_bin_get_type (void); G_END_DECLS