diff --git a/ges/Makefile.am b/ges/Makefile.am
index 7ba4a26c75..9642e3a315 100644
--- a/ges/Makefile.am
+++ b/ges/Makefile.am
@@ -63,7 +63,8 @@ libges_@GST_API_VERSION@_la_SOURCES = \
ges-effect-asset.c \
ges-smart-adder.c \
ges-smart-video-mixer.c \
- ges-utils.c
+ ges-utils.c \
+ gstframepositionner.c
libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/
libges_@GST_API_VERSION@include_HEADERS = \
@@ -123,7 +124,8 @@ libges_@GST_API_VERSION@include_HEADERS = \
ges-effect-asset.h \
ges-smart-adder.h \
ges-smart-video-mixer.h \
- ges-utils.h
+ ges-utils.h \
+ gstframepositionner.h
noinst_HEADERS = \
ges-internal.h \
diff --git a/ges/ges-smart-video-mixer.c b/ges/ges-smart-video-mixer.c
index 8da61bfac5..a318843e2f 100644
--- a/ges/ges-smart-video-mixer.c
+++ b/ges/ges-smart-video-mixer.c
@@ -17,6 +17,7 @@
* along with this program. If not, see .";
*/
+#include "gstframepositionner.h"
#include "ges-types.h"
#include "ges-internal.h"
#include "ges-smart-video-mixer.h"
@@ -44,11 +45,14 @@ typedef struct _PadInfos
GESSmartMixer *self;
GstPad *mixer_pad;
GstElement *bin;
+ gulong probe_id;
} PadInfos;
static void
destroy_pad (PadInfos * infos)
{
+ gst_pad_remove_probe (infos->mixer_pad, infos->probe_id);
+
if (G_LIKELY (infos->bin)) {
gst_element_set_state (infos->bin, GST_STATE_NULL);
gst_element_unlink (infos->bin, infos->self->mixer);
@@ -57,9 +61,32 @@ destroy_pad (PadInfos * infos)
if (infos->mixer_pad)
gst_element_release_request_pad (infos->self->mixer, infos->mixer_pad);
+
g_slice_free (PadInfos, infos);
}
+/* These metadata will get set by the upstream framepositionner element,
+ added in the video sources' bin */
+static GstPadProbeReturn
+parse_metadata (GstPad * mixer_pad, GstPadProbeInfo * info, gpointer unused)
+{
+ GstFramePositionnerMeta *meta;
+
+ meta =
+ (GstFramePositionnerMeta *) gst_buffer_get_meta ((GstBuffer *) info->data,
+ gst_frame_positionner_meta_api_get_type ());
+
+ if (!meta) {
+ GST_WARNING ("The current source should use a framepositionner");
+ return GST_PAD_PROBE_OK;
+ }
+
+ g_object_set (mixer_pad, "alpha", meta->alpha, "xpos", meta->posx, "ypos",
+ meta->posy, "zorder", meta->zorder, NULL);
+
+ return GST_PAD_PROBE_OK;
+}
+
/****************************************************
* GstElement vmetods *
****************************************************/
@@ -77,8 +104,6 @@ _request_new_pad (GstElement * element, GstPadTemplate * templ,
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");
@@ -111,6 +136,10 @@ _request_new_pad (GstElement * element, GstPadTemplate * templ,
gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost);
gst_pad_link (tmpghost, infos->mixer_pad);
+ infos->probe_id =
+ gst_pad_add_probe (infos->mixer_pad, GST_PAD_PROBE_TYPE_BUFFER,
+ (GstPadProbeCallback) parse_metadata, NULL, NULL);
+
LOCK (self);
g_hash_table_insert (self->pads_infos, ghost, infos);
UNLOCK (self);
diff --git a/ges/ges-uri-source.c b/ges/ges-uri-source.c
index 251a5e026e..000e8ac761 100644
--- a/ges/ges-uri-source.c
+++ b/ges/ges-uri-source.c
@@ -32,10 +32,13 @@
#include "ges-uri-source.h"
#include "ges-uri-asset.h"
#include "ges-extractable.h"
+#include "ges-layer.h"
+#include "gstframepositionner.h"
struct _GESUriSourcePrivate
{
GHashTable *props_hashtable;
+ GstFramePositionner *positionner;
};
enum
@@ -185,6 +188,23 @@ _sync_element_to_layer_property_float (GESTrackElement * trksrc,
/* TrackElement VMethods */
+static void
+update_z_order_cb (GESClip * clip, GParamSpec * arg G_GNUC_UNUSED,
+ GESUriSource * self)
+{
+ GESLayer *layer = ges_clip_get_layer (clip);
+
+ if (layer == NULL)
+ return;
+
+ /* 10000 is the max value of zorder on videomixerpad, hardcoded */
+
+ g_object_set (self->priv->positionner, "zorder",
+ 10000 - ges_layer_get_priority (layer), NULL);
+
+ gst_object_unref (layer);
+}
+
static GstElement *
ges_uri_source_create_element (GESTrackElement * trksrc)
{
@@ -192,6 +212,8 @@ ges_uri_source_create_element (GESTrackElement * trksrc)
GESTrack *track;
GstElement *decodebin;
GstElement *topbin, *volume;
+ GstElement *positionner;
+ GESTimelineElement *parent;
self = (GESUriSource *) trksrc;
track = ges_track_element_get_track (trksrc);
@@ -210,6 +232,27 @@ ges_uri_source_create_element (GESTrackElement * trksrc)
_add_element_properties_to_hashtable (self, volume, "volume", "mute",
NULL);
break;
+ case GES_TRACK_TYPE_VIDEO:
+ decodebin = gst_element_factory_make ("uridecodebin", NULL);
+
+ /* That positionner will add metadata to buffers according to its
+ properties, acting like a proxy for our smart-mixer dynamic pads. */
+ positionner =
+ gst_element_factory_make ("framepositionner", "frame_tagger");
+ _add_element_properties_to_hashtable (self, positionner, "alpha", "posx",
+ "posy", NULL);
+ topbin = _create_bin ("video-src-bin", decodebin, positionner, NULL);
+ parent = ges_timeline_element_get_parent (GES_TIMELINE_ELEMENT (trksrc));
+ if (parent) {
+ self->priv->positionner = GST_FRAME_POSITIONNER (positionner);
+ g_signal_connect (parent, "notify::layer",
+ (GCallback) update_z_order_cb, trksrc);
+ update_z_order_cb (GES_CLIP (parent), NULL, self);
+ gst_object_unref (parent);
+ } else {
+ GST_WARNING ("No parent timeline element, SHOULD NOT HAPPEN");
+ }
+ break;
default:
decodebin = gst_element_factory_make ("uridecodebin", NULL);
topbin = _create_bin ("video-src-bin", decodebin, NULL);
@@ -347,6 +390,7 @@ ges_track_filesource_init (GESUriSource * self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
GES_TYPE_URI_SOURCE, GESUriSourcePrivate);
self->priv->props_hashtable = NULL;
+ self->priv->positionner = NULL;
}
/**
diff --git a/ges/ges.c b/ges/ges.c
index d59664faec..2b4b54c491 100644
--- a/ges/ges.c
+++ b/ges/ges.c
@@ -19,6 +19,7 @@
*/
#include
+#include "ges/gstframepositionner.h"
#include "ges-internal.h"
#define GES_GNONLIN_VERSION_NEEDED_MAJOR 0
@@ -93,6 +94,9 @@ ges_init (void)
if (!ges_check_gnonlin_availability ())
return FALSE;
+ gst_element_register (NULL, "framepositionner", 0,
+ GST_TYPE_FRAME_POSITIONNER);
+
/* TODO: user-defined types? */
ges_initialized = TRUE;
diff --git a/ges/gstframepositionner.c b/ges/gstframepositionner.c
new file mode 100644
index 0000000000..120451509b
--- /dev/null
+++ b/ges/gstframepositionner.c
@@ -0,0 +1,263 @@
+/* GStreamer
+ * Copyright (C) 2013 Mathieu Duponchelle
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
+ * Boston, MA 02110-1335, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include "gstframepositionner.h"
+
+static void gst_frame_positionner_set_property (GObject * object,
+ guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_frame_positionner_get_property (GObject * object,
+ guint property_id, GValue * value, GParamSpec * pspec);
+static GstFlowReturn gst_frame_positionner_transform_ip (GstBaseTransform *
+ trans, GstBuffer * buf);
+
+static gboolean
+gst_frame_positionner_meta_transform (GstBuffer * dest, GstMeta * meta,
+ GstBuffer * buffer, GQuark type, gpointer data);
+
+enum
+{
+ PROP_0,
+ PROP_ALPHA,
+ PROP_POSX,
+ PROP_POSY,
+ PROP_ZORDER
+};
+
+static GstStaticPadTemplate gst_frame_positionner_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw")
+ );
+
+static GstStaticPadTemplate gst_frame_positionner_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw")
+ );
+
+G_DEFINE_TYPE (GstFramePositionner, gst_frame_positionner,
+ GST_TYPE_BASE_TRANSFORM);
+
+static void
+gst_frame_positionner_class_init (GstFramePositionnerClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseTransformClass *base_transform_class =
+ GST_BASE_TRANSFORM_CLASS (klass);
+
+ gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
+ gst_static_pad_template_get (&gst_frame_positionner_src_template));
+ gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
+ gst_static_pad_template_get (&gst_frame_positionner_sink_template));
+
+ gobject_class->set_property = gst_frame_positionner_set_property;
+ gobject_class->get_property = gst_frame_positionner_get_property;
+ base_transform_class->transform_ip =
+ GST_DEBUG_FUNCPTR (gst_frame_positionner_transform_ip);
+
+ /**
+ * gstframepositionner:alpha:
+ *
+ * The desired alpha for the stream.
+ */
+ g_object_class_install_property (gobject_class, PROP_ALPHA,
+ g_param_spec_double ("alpha", "alpha", "alpha of the stream",
+ 0.0, 1.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ /**
+ * gstframepositionner:posx:
+ *
+ * The desired x position for the stream.
+ */
+ g_object_class_install_property (gobject_class, PROP_ALPHA,
+ g_param_spec_int ("posx", "posx", "x position of the stream",
+ G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ /**
+ * gstframepositionner:posy:
+ *
+ * The desired y position for the stream.
+ */
+ g_object_class_install_property (gobject_class, PROP_ALPHA,
+ g_param_spec_int ("posy", "posy", "y position of the stream",
+ G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ /**
+ * gstframepositionner:zorder:
+ *
+ * The desired z order for the stream.
+ */
+ g_object_class_install_property (gobject_class, PROP_ZORDER,
+ g_param_spec_uint ("zorder", "zorder", "z order of the stream",
+ 0, 10000, 0, G_PARAM_READWRITE));
+
+ gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
+ "frame positionner", "Metadata",
+ "This element provides with tagging facilities",
+ "mduponchelle1@gmail.com");
+}
+
+static void
+gst_frame_positionner_init (GstFramePositionner * framepositionner)
+{
+ framepositionner->alpha = 1.0;
+ framepositionner->posx = 0.0;
+ framepositionner->posy = 0.0;
+ framepositionner->zorder = 0;
+}
+
+void
+gst_frame_positionner_set_property (GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstFramePositionner *framepositionner = GST_FRAME_POSITIONNER (object);
+
+
+ GST_OBJECT_LOCK (framepositionner);
+ switch (property_id) {
+ case PROP_ALPHA:
+ framepositionner->alpha = g_value_get_double (value);
+ break;
+ case PROP_POSX:
+ framepositionner->posx = g_value_get_int (value);
+ break;
+ case PROP_POSY:
+ framepositionner->posy = g_value_get_int (value);
+ break;
+ case PROP_ZORDER:
+ framepositionner->zorder = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (framepositionner);
+}
+
+void
+gst_frame_positionner_get_property (GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstFramePositionner *framepositionner = GST_FRAME_POSITIONNER (object);
+
+ GST_DEBUG_OBJECT (framepositionner, "get_property");
+
+ switch (property_id) {
+ case PROP_ALPHA:
+ g_value_set_double (value, framepositionner->alpha);
+ break;
+ case PROP_POSX:
+ g_value_set_int (value, framepositionner->posx);
+ break;
+ case PROP_POSY:
+ g_value_set_int (value, framepositionner->posy);
+ break;
+ case PROP_ZORDER:
+ g_value_set_uint (value, framepositionner->zorder);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+GType
+gst_frame_positionner_meta_api_get_type (void)
+{
+ static volatile GType type;
+ static const gchar *tags[] = { "alpha", "posx", "posy", "zorder", NULL };
+
+ if (g_once_init_enter (&type)) {
+ GType _type = gst_meta_api_type_register ("GstFramePositionnerApi", tags);
+ g_once_init_leave (&type, _type);
+ }
+ return type;
+}
+
+static const GstMetaInfo *
+gst_frame_positionner_get_info (void)
+{
+ static const GstMetaInfo *meta_info = NULL;
+
+ if (g_once_init_enter (&meta_info)) {
+ const GstMetaInfo *meta =
+ gst_meta_register (gst_frame_positionner_meta_api_get_type (),
+ "GstFramePositionnerMeta",
+ sizeof (GstFramePositionnerMeta), (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) NULL,
+ (GstMetaTransformFunction) gst_frame_positionner_meta_transform);
+ g_once_init_leave (&meta_info, meta);
+ }
+ return meta_info;
+}
+
+static gboolean
+gst_frame_positionner_meta_transform (GstBuffer * dest, GstMeta * meta,
+ GstBuffer * buffer, GQuark type, gpointer data)
+{
+ GstFramePositionnerMeta *dmeta, *smeta;
+
+ smeta = (GstFramePositionnerMeta *) meta;
+
+ if (GST_META_TRANSFORM_IS_COPY (type)) {
+ /* only copy if the complete data is copied as well */
+ dmeta =
+ (GstFramePositionnerMeta *) gst_buffer_add_meta (dest,
+ gst_frame_positionner_get_info (), NULL);
+ dmeta->alpha = smeta->alpha;
+ dmeta->posx = smeta->posx;
+ dmeta->posy = smeta->posy;
+ dmeta->zorder = smeta->zorder;
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_frame_positionner_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
+{
+ GstFramePositionnerMeta *meta;
+ GstFramePositionner *framepositionner = GST_FRAME_POSITIONNER (trans);
+ GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ gst_object_sync_values (GST_OBJECT (trans), timestamp);
+ }
+
+ meta =
+ (GstFramePositionnerMeta *) gst_buffer_add_meta (buf,
+ gst_frame_positionner_get_info (), NULL);
+
+ GST_OBJECT_LOCK (framepositionner);
+ meta->alpha = framepositionner->alpha;
+ meta->posx = framepositionner->posx;
+ meta->posy = framepositionner->posy;
+ meta->zorder = framepositionner->zorder;
+ GST_OBJECT_UNLOCK (framepositionner);
+
+ return GST_FLOW_OK;
+}
diff --git a/ges/gstframepositionner.h b/ges/gstframepositionner.h
new file mode 100644
index 0000000000..502c9efaf5
--- /dev/null
+++ b/ges/gstframepositionner.h
@@ -0,0 +1,67 @@
+/* GStreamer
+ * Copyright (C) 2013 Mathieu Duponchelle
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_FRAME_POSITIONNER_H_
+#define _GST_FRAME_POSITIONNER_H_
+
+#include
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_FRAME_POSITIONNER (gst_frame_positionner_get_type())
+#define GST_FRAME_POSITIONNER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FRAME_POSITIONNER,GstFramePositionner))
+#define GST_FRAME_POSITIONNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FRAME_POSITIONNER,GstFramePositionnerClass))
+#define GST_IS_FRAME_POSITIONNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FRAME_POSITIONNER))
+#define GST_IS_FRAME_POSITIONNER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FRAME_POSITIONNER))
+
+typedef struct _GstFramePositionner GstFramePositionner;
+typedef struct _GstFramePositionnerClass GstFramePositionnerClass;
+typedef struct _GstFramePositionnerMeta GstFramePositionnerMeta;
+
+struct _GstFramePositionner
+{
+ GstBaseTransform base_framepositionner;
+
+ gdouble alpha;
+ gint posx;
+ gint posy;
+ guint zorder;
+};
+
+struct _GstFramePositionnerClass
+{
+ GstBaseTransformClass base_framepositionner_class;
+};
+
+struct _GstFramePositionnerMeta {
+ GstMeta meta;
+
+ gdouble alpha;
+ gint posx;
+ gint posy;
+ guint zorder;
+};
+
+GType gst_frame_positionner_get_type (void);
+GType
+gst_frame_positionner_meta_api_get_type (void);
+
+G_END_DECLS
+
+#endif