diff --git a/ges/Makefile.am b/ges/Makefile.am index 66f8d6f04f..7ba4a26c75 100644 --- a/ges/Makefile.am +++ b/ges/Makefile.am @@ -62,6 +62,7 @@ libges_@GST_API_VERSION@_la_SOURCES = \ ges-container.c \ ges-effect-asset.c \ ges-smart-adder.c \ + ges-smart-video-mixer.c \ ges-utils.c libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/ @@ -121,6 +122,7 @@ libges_@GST_API_VERSION@include_HEADERS = \ ges-container.h \ ges-effect-asset.h \ ges-smart-adder.h \ + ges-smart-video-mixer.h \ ges-utils.h noinst_HEADERS = \ diff --git a/ges/ges-smart-video-mixer.c b/ges/ges-smart-video-mixer.c new file mode 100644 index 0000000000..8da61bfac5 --- /dev/null +++ b/ges/ges-smart-video-mixer.c @@ -0,0 +1,205 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * gst-editing-services + * + * Copyright (C) 2013 Mathieu Duponchelle + * gst-editing-services is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gst-editing-services is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + */ + +#include "ges-types.h" +#include "ges-internal.h" +#include "ges-smart-video-mixer.h" + +G_DEFINE_TYPE (GESSmartMixer, ges_smart_mixer, GST_TYPE_BIN); + +#define GET_LOCK(obj) (&((GESSmartMixer*)(obj))->lock) +#define LOCK(obj) (g_mutex_lock (GET_LOCK(obj))) +#define UNLOCK(obj) (g_mutex_unlock (GET_LOCK(obj))) + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw") + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("video/x-raw") + ); + +typedef struct _PadInfos +{ + GESSmartMixer *self; + GstPad *mixer_pad; + GstElement *bin; +} PadInfos; + +static void +destroy_pad (PadInfos * infos) +{ + if (G_LIKELY (infos->bin)) { + gst_element_set_state (infos->bin, GST_STATE_NULL); + gst_element_unlink (infos->bin, infos->self->mixer); + gst_bin_remove (GST_BIN (infos->self), infos->bin); + } + + if (infos->mixer_pad) + gst_element_release_request_pad (infos->self->mixer, infos->mixer_pad); + g_slice_free (PadInfos, infos); +} + +/**************************************************** + * GstElement vmetods * + ****************************************************/ +static GstPad * +_request_new_pad (GstElement * element, GstPadTemplate * templ, + const gchar * name, const GstCaps * caps) +{ + GstPad *videoconvert_srcpad, *videoconvert_sinkpad, *tmpghost; + PadInfos *infos = g_slice_new0 (PadInfos); + GESSmartMixer *self = GES_SMART_MIXER (element); + GstPad *ghost; + GstElement *videoconvert; + + infos->mixer_pad = gst_element_request_pad (self->mixer, + gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (self->mixer), + "sink_%u"), NULL, NULL); + + g_object_set (G_OBJECT (infos->mixer_pad), "alpha", 0.5, NULL); + + if (infos->mixer_pad == NULL) { + GST_WARNING_OBJECT (element, "Could not get any pad from GstMixer"); + + return NULL; + } + + infos->self = self; + + infos->bin = gst_bin_new (NULL); + videoconvert = gst_element_factory_make ("videoconvert", NULL); + + gst_bin_add (GST_BIN (infos->bin), videoconvert); + + videoconvert_sinkpad = gst_element_get_static_pad (videoconvert, "sink"); + tmpghost = GST_PAD (gst_ghost_pad_new (NULL, videoconvert_sinkpad)); + gst_object_unref (videoconvert_sinkpad); + gst_pad_set_active (tmpghost, TRUE); + gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost); + + gst_bin_add (GST_BIN (self), infos->bin); + ghost = gst_ghost_pad_new (NULL, tmpghost); + gst_pad_set_active (ghost, TRUE); + if (!gst_element_add_pad (GST_ELEMENT (self), ghost)) + goto could_not_add; + + videoconvert_srcpad = gst_element_get_static_pad (videoconvert, "src"); + tmpghost = GST_PAD (gst_ghost_pad_new (NULL, videoconvert_srcpad)); + gst_object_unref (videoconvert_srcpad); + gst_pad_set_active (tmpghost, TRUE); + gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost); + gst_pad_link (tmpghost, infos->mixer_pad); + + LOCK (self); + g_hash_table_insert (self->pads_infos, ghost, infos); + UNLOCK (self); + + GST_DEBUG_OBJECT (self, "Returning new pad %" GST_PTR_FORMAT, ghost); + return ghost; + +could_not_add: + { + GST_ERROR_OBJECT (self, "could not add pad"); + destroy_pad (infos); + return NULL; + } +} + +static void +_release_pad (GstElement * element, GstPad * pad) +{ + GST_DEBUG_OBJECT (element, "Releasing pad %" GST_PTR_FORMAT, pad); + + LOCK (element); + g_hash_table_remove (GES_SMART_MIXER (element)->pads_infos, pad); + UNLOCK (element); +} + +/**************************************************** + * GObject vmethods * + ****************************************************/ +static void +ges_smart_mixer_finalize (GObject * object) +{ + GESSmartMixer *self = GES_SMART_MIXER (object); + + g_mutex_clear (&self->lock); + + G_OBJECT_CLASS (ges_smart_mixer_parent_class)->finalize (object); +} + +static void +ges_smart_mixer_class_init (GESSmartMixerClass * klass) +{ +/* GstBinClass *parent_class = GST_BIN_CLASS (klass); + */ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + /* FIXME Make sure the MixerClass doesn get destroy before ourself */ + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_set_static_metadata (element_class, "GES Smart mixer", + "Generic/Audio", + "Use mixer making use of GES informations", + "Thibault Saunier "); + + element_class->request_new_pad = GST_DEBUG_FUNCPTR (_request_new_pad); + element_class->release_pad = GST_DEBUG_FUNCPTR (_release_pad); + + object_class->finalize = ges_smart_mixer_finalize; +} + +static void +ges_smart_mixer_init (GESSmartMixer * self) +{ + GstPad *pad; + + g_mutex_init (&self->lock); + + self->mixer = gst_element_factory_make ("videomixer", "smart-mixer-mixer"); + g_object_set (self->mixer, "background", 1, NULL); + gst_bin_add (GST_BIN (self), self->mixer); + + pad = gst_element_get_static_pad (self->mixer, "src"); + self->srcpad = gst_ghost_pad_new ("src", pad); + gst_pad_set_active (self->srcpad, TRUE); + + gst_element_add_pad (GST_ELEMENT (self), self->srcpad); + + self->pads_infos = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) destroy_pad); +} + +GstElement * +ges_smart_mixer_new (GESTrack * track) +{ + GESSmartMixer *self = g_object_new (GES_TYPE_SMART_MIXER, NULL); + self->track = track; + + /* FIXME Make mixer smart and let it properly negotiate caps! */ + return GST_ELEMENT (self); +} diff --git a/ges/ges-smart-video-mixer.h b/ges/ges-smart-video-mixer.h new file mode 100644 index 0000000000..d5539fab11 --- /dev/null +++ b/ges/ges-smart-video-mixer.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * gst-editing-services + * Copyright (C) 2013 Mathieu Duponchelle + * + * gst-editing-services is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gst-editing-services is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see ."; + */ + +#ifndef _GES_SMART_MIXER_H_ +#define _GES_SMART_MIXER_H_ + +#include +#include + +#include "ges-track.h" + +G_BEGIN_DECLS + +#define GES_TYPE_SMART_MIXER (ges_smart_mixer_get_type ()) +#define GES_SMART_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_SMART_MIXER, GESSmartMixer)) +#define GES_SMART_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_SMART_MIXER, GESSmartMixerClass)) +#define GES_IS_SMART_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_SMART_MIXER)) +#define GES_IS_SMART_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_SMART_MIXER)) +#define GES_SMART_MIXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_SMART_MIXER, GESSmartMixerClass)) + +typedef struct _GESSmartMixerClass GESSmartMixerClass; +typedef struct _GESSmartMixer GESSmartMixer; + +struct _GESSmartMixerClass +{ + GstBinClass parent_class; +}; + +struct _GESSmartMixer +{ + GstBin parent_instance; + + GHashTable *pads_infos; + GstPad *srcpad; + GstElement *mixer; + GMutex lock; + + GstCaps *caps; + + GESTrack *track; +}; + +GType ges_smart_mixer_get_type (void) G_GNUC_CONST; +GstElement* ges_smart_mixer_new (GESTrack *track); + +G_END_DECLS +#endif /* _GES_SMART_MIXER_H_ */ diff --git a/ges/ges-video-track.h b/ges/ges-video-track.h index e6c422ad8d..743f3070d3 100644 --- a/ges/ges-video-track.h +++ b/ges/ges-video-track.h @@ -38,13 +38,20 @@ typedef struct _GESVideoTrackPrivate GESVideoTrackPrivate; struct _GESVideoTrackClass { GESTrackClass parent_class; + + /* Padding for API extension */ + gpointer _ges_reserved[GES_PADDING]; }; struct _GESVideoTrack { GESTrack parent_instance; + /*< private >*/ GESVideoTrackPrivate *priv; + + /* Padding for API extension */ + gpointer _ges_reserved[GES_PADDING]; }; GType ges_video_track_get_type (void) G_GNUC_CONST;