ges-timeline-element.c \
ges-container.c \
ges-effect-asset.c \
+ ges-smart-adder.c \
ges-utils.c
libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/
ges-timeline-element.h \
ges-container.h \
ges-effect-asset.h \
+ ges-smart-adder.h \
ges-utils.h
noinst_HEADERS = \
* @short_description: A standard GESTrack for raw audio
*/
-#include "ges-audio-track.h"
-
#define DEFAULT_CAPS "audio/x-raw"
+#include "ges-smart-adder.h"
+#include "ges-audio-track.h"
+
struct _GESAudioTrackPrivate
{
gpointer nothing;
g_type_class_add_private (klass, sizeof (GESAudioTrackPrivate));
object_class->finalize = ges_audio_track_finalize;
+
+ GES_TRACK_CLASS (klass)->get_mixing_element = ges_smart_adder_new;
}
/****************************************************
struct _GESAudioTrackClass
{
GESTrackClass parent_class;
+
+ /* Padding for API extension */
+ gpointer _ges_reserved[GES_PADDING];
};
struct _GESAudioTrack
{
GESTrack parent_instance;
+ /*< private >*/
GESAudioTrackPrivate *priv;
+ /* Padding for API extension */
+ gpointer _ges_reserved[GES_PADDING];
};
GType ges_audio_track_get_type (void) G_GNUC_CONST;
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gst-editing-services
+ *
+ * Copyright (C) 2013 Thibault Saunier <tsaunier@gnome.org>
+
+ * 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 <http://www.gnu.org/licenses/>.";
+ */
+#include <gst/audio/audio.h>
+
+#include "ges-types.h"
+#include "ges-internal.h"
+#include "ges-smart-adder.h"
+
+G_DEFINE_TYPE (GESSmartAdder, ges_smart_adder, GST_TYPE_BIN);
+
+#define GET_LOCK(obj) (&((GESSmartAdder*)(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 ("audio/x-raw")
+ );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ("audio/x-raw")
+ );
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define DEFAULT_CAPS "audio/x-raw,format=(string)S32LE;"
+#else
+#define DEFAULT_CAPS "audio/x-raw,format=(string)S32BE;";
+#endif
+
+typedef struct _PadInfos
+{
+ GESSmartAdder *self;
+ GstPad *ghost;
+ GstPad *adder_pad;
+ GstPad *parent_sinkpad;
+
+ GstElement *volume;
+ GstElement *audioconvert;
+ GstElement *audioresample;
+ GstElement *bin;
+
+} PadInfos;
+
+static void
+destroy_pad_info (PadInfos * infos)
+{
+ GST_DEBUG_OBJECT (infos->self, "Destroying pad %" GST_PTR_FORMAT,
+ infos->ghost);
+
+ if (G_LIKELY (infos->bin)) {
+ gst_element_set_state (infos->bin, GST_STATE_NULL);
+ gst_element_unlink (infos->bin, infos->self->adder);
+ gst_bin_remove (GST_BIN (infos->self), infos->bin);
+ }
+
+ if (infos->adder_pad)
+ gst_element_release_request_pad (infos->self->adder, infos->adder_pad);
+
+ g_slice_free (PadInfos, infos);
+}
+
+/****************************************************
+ * Callbacks *
+ ****************************************************/
+static void
+_connected_to_gnlobject_cb (GstPad * pad, GstPad * peer, PadInfos * infos)
+{
+ GESTrack *track;
+ GESLayer *layer;
+
+ gfloat volume, track_volume, layer_volume;
+ GstElement *gnlobject = gst_pad_get_parent_element (peer);
+ GESTrackElement *track_element = g_object_get_qdata (G_OBJECT (gnlobject),
+ GNL_OBJECT_TRACK_ELEMENT_QUARK);
+
+ g_assert (track_element);
+ g_signal_handlers_disconnect_by_func (pad, _connected_to_gnlobject_cb, infos);
+
+ volume = track_volume = layer_volume = GES_META_VOLUME_DEFAULT;
+ track = ges_track_element_get_track (track_element);
+ layer = ges_clip_get_layer (GES_CLIP (GES_TIMELINE_ELEMENT_PARENT
+ (track_element)));
+
+ if (layer == NULL) {
+ GST_WARNING ("TrackElement is in no layer");
+ goto no_layer;
+ }
+
+ ges_meta_container_get_float (GES_META_CONTAINER (layer),
+ GES_META_VOLUME, &layer_volume);
+ gst_object_unref (layer);
+ ges_meta_container_get_float (GES_META_CONTAINER (track),
+ GES_META_VOLUME, &track_volume);
+
+ volume = track_volume * layer_volume;
+ g_object_set (infos->volume, "volume", volume, NULL);
+
+no_layer:
+ gst_object_unref (gnlobject);
+}
+
+/* Here we get the information that the pad is linked to a ghostpad GNL created,
+ * what we want is to get notify when the gnloperation (ghost)sinkpad gets linked
+ * to the pad of another gnlobject in the pipeline, so we can get the
+ * GESTrackElement that wraps the gnlobject that is linked */
+static void
+_sink_pad_linked_cb (GstPad * adder_pad, GstProxyPad * peer, PadInfos * infos)
+{
+ GESSmartAdder *self = infos->self;
+ /* The peer is a ProxyPad (inside ourself) that is linked to the gnloperation
+ * ProxyPad, we want to get notify about the gnloperation ProxyPad connection
+ */
+ GstProxyPad *parent_sinkpad =
+ gst_proxy_pad_get_internal (GST_PROXY_PAD (peer));
+
+ LOCK (self);
+ infos->parent_sinkpad = GST_PAD (parent_sinkpad);
+ UNLOCK (self);
+
+ g_signal_handlers_disconnect_by_func (adder_pad, _sink_pad_linked_cb, infos);
+ g_signal_connect (parent_sinkpad, "linked",
+ G_CALLBACK (_connected_to_gnlobject_cb), infos);
+}
+
+
+/****************************************************
+ * GstElement vmetods *
+ ****************************************************/
+static GstPad *
+_request_new_pad (GstElement * element, GstPadTemplate * templ,
+ const gchar * name, const GstCaps * caps)
+{
+ GstPad *volume_srcpad, *audioconvert_sinkpad, *tmpghost;
+
+ PadInfos *infos = g_slice_new0 (PadInfos);
+ GESSmartAdder *self = GES_SMART_ADDER (element);
+
+ infos->adder_pad = gst_element_request_pad (self->adder, templ, NULL, caps);
+ if (infos->adder_pad == NULL) {
+ GST_WARNING_OBJECT (element, "Could not get any pad from GstAdder");
+
+ return NULL;
+ }
+ infos->self = gst_object_ref (self);
+
+ infos->bin = gst_bin_new (NULL);
+ infos->audioconvert = gst_element_factory_make ("audioconvert", NULL);
+ infos->audioresample = gst_element_factory_make ("audioresample", NULL);
+ infos->volume = gst_element_factory_make ("volume", NULL);
+ gst_bin_add_many (GST_BIN (infos->bin), infos->audioconvert,
+ infos->audioresample, infos->volume, NULL);
+ gst_element_link_many (infos->audioconvert, infos->audioresample,
+ infos->volume, NULL);
+
+ audioconvert_sinkpad = gst_element_get_static_pad (infos->audioconvert,
+ "sink");
+ tmpghost = GST_PAD (gst_ghost_pad_new (NULL, audioconvert_sinkpad));
+ gst_object_unref (audioconvert_sinkpad);
+ gst_pad_set_active (tmpghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost);
+
+ gst_bin_add (GST_BIN (self), infos->bin);
+ infos->ghost = gst_ghost_pad_new (NULL, tmpghost);
+ gst_pad_set_active (infos->ghost, TRUE);
+ if (!gst_element_add_pad (GST_ELEMENT (self), infos->ghost))
+ goto could_not_add;
+
+
+ volume_srcpad = gst_element_get_static_pad (infos->volume, "src");
+ tmpghost = GST_PAD (gst_ghost_pad_new (NULL, volume_srcpad));
+ gst_object_unref (volume_srcpad);
+ gst_pad_set_active (tmpghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost);
+ gst_pad_link (tmpghost, infos->adder_pad);
+
+ LOCK (self);
+ g_hash_table_insert (self->pads_infos, infos->ghost, infos);
+ UNLOCK (self);
+
+ g_signal_connect (infos->ghost, "linked",
+ G_CALLBACK (_sink_pad_linked_cb), infos);
+
+ GST_DEBUG_OBJECT (self, "Returning new pad %" GST_PTR_FORMAT, infos->ghost);
+ return infos->ghost;
+
+could_not_add:
+ {
+ GST_DEBUG_OBJECT (self, "could not add pad");
+ destroy_pad_info (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_ADDER (element)->pads_infos, pad);
+ UNLOCK (element);
+}
+
+/****************************************************
+ * GObject vmethods *
+ ****************************************************/
+static void
+ges_smart_adder_finalize (GObject * object)
+{
+ GESSmartAdder *self = GES_SMART_ADDER (object);
+
+ g_mutex_clear (&self->lock);
+
+ G_OBJECT_CLASS (ges_smart_adder_parent_class)->finalize (object);
+}
+
+static void
+ges_smart_adder_class_init (GESSmartAdderClass * 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 AdderClass 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 adder",
+ "Generic/Audio",
+ "Use adder making use of GES informations",
+ "Thibault Saunier <thibault.saunier@collabora.com>");
+
+ 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_adder_finalize;
+}
+
+static void
+ges_smart_adder_init (GESSmartAdder * self)
+{
+ GstPad *pad;
+
+ g_mutex_init (&self->lock);
+
+ self->adder = gst_element_factory_make ("adder", "smart-adder-adder");
+ gst_bin_add (GST_BIN (self), self->adder);
+
+ pad = gst_element_get_static_pad (self->adder, "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_info);
+}
+
+GstElement *
+ges_smart_adder_new (GESTrack * track)
+{
+ GESSmartAdder *self = g_object_new (GES_TYPE_SMART_ADDER, NULL);
+ self->track = track;
+
+ /* FIXME Make adder smart and let it properly negotiate caps! */
+ g_object_set (self->adder, "caps", gst_caps_from_string (DEFAULT_CAPS), NULL);
+ return GST_ELEMENT (self);
+}
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gst-editing-services
+ * Copyright (C) 2013 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.";
+ */
+
+#ifndef _GES_SMART_ADDER_H_
+#define _GES_SMART_ADDER_H_
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include "ges-track.h"
+
+G_BEGIN_DECLS
+
+#define GES_TYPE_SMART_ADDER (ges_smart_adder_get_type ())
+#define GES_SMART_ADDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_SMART_ADDER, GESSmartAdder))
+#define GES_SMART_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_SMART_ADDER, GESSmartAdderClass))
+#define GES_IS_SMART_ADDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_SMART_ADDER))
+#define GES_IS_SMART_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_SMART_ADDER))
+#define GES_SMART_ADDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_SMART_ADDER, GESSmartAdderClass))
+
+typedef struct _GESSmartAdderClass GESSmartAdderClass;
+typedef struct _GESSmartAdder GESSmartAdder;
+
+struct _GESSmartAdderClass
+{
+ GstBinClass parent_class;
+};
+
+struct _GESSmartAdder
+{
+ GstBin parent_instance;
+
+ GHashTable *pads_infos;
+ GstPad *srcpad;
+ GstElement *adder;
+ GMutex lock;
+
+ GstCaps *caps;
+
+ GESTrack *track;
+};
+
+GType ges_smart_adder_get_type (void) G_GNUC_CONST;
+GstElement* ges_smart_adder_new (GESTrack *track);
+
+G_END_DECLS
+#endif /* _GES_SMART_ADDER_H_ */
}
static void
+ges_track_constructed (GObject * object)
+{
+ GESTrack *self = GES_TRACK (object);
+
+ if (!gst_bin_add (GST_BIN (self), self->priv->composition))
+ GST_ERROR ("Couldn't add composition to bin !");
+
+ if (GES_TRACK_GET_CLASS (self)->get_mixing_element) {
+ GstElement *gnlobject;
+ GstElement *mixer = GES_TRACK_GET_CLASS (self)->get_mixing_element (self);
+
+ if (mixer == NULL) {
+ GST_WARNING_OBJECT (self, "Got no element fron get_mixing_element");
+
+ return;
+ }
+
+ gnlobject = gst_element_factory_make ("gnloperation", "mixing-operation");
+ if (!gst_bin_add (GST_BIN (gnlobject), mixer)) {
+ GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
+
+ return;
+ }
+ g_object_set (gnlobject, "expandable", TRUE, NULL);
+
+ if (!gst_bin_add (GST_BIN (self->priv->composition), gnlobject)) {
+ GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
+
+ return;
+ }
+ } else {
+ GST_INFO_OBJECT (self, "No way to create a main mixer");
+ }
+}
+
+static void
ges_track_class_init (GESTrackClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = ges_track_set_property;
object_class->dispose = ges_track_dispose;
object_class->finalize = ges_track_finalize;
+ object_class->constructed = ges_track_constructed;
/**
* GESTrack:caps:
(GCallback) pad_added_cb, self);
g_signal_connect (self->priv->composition, "pad-removed",
(GCallback) pad_removed_cb, self);
-
- if (!gst_bin_add (GST_BIN (self), self->priv->composition))
- GST_ERROR ("Couldn't add composition to bin !");
-
- if (GES_TRACK_GET_CLASS (self)->get_mixing_element) {
- GstElement *gnlobject;
- GstElement *mixer = GES_TRACK_GET_CLASS (self)->get_mixing_element (self);
-
- if (mixer == NULL) {
- GST_WARNING_OBJECT (self, "Got no element fron get_mixing_element");
-
- return;
- }
-
- gnlobject = gst_element_factory_make ("gnloperation", "mixing-operation");
- if (!gst_bin_add (GST_BIN (gnlobject), mixer)) {
- GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
-
- return;
- }
- g_object_set (gnlobject, "start", GST_CLOCK_TIME_NONE, "duration",
- GST_CLOCK_TIME_NONE, "prioirity", 0, NULL);
-
- if (!gst_bin_add (GST_BIN (self->priv->composition), gnlobject)) {
- GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
-
- return;
- }
- }
}
/**
ges/transition \
ges/overlays\
ges/text_properties\
+ ges/mixers\
ges/project
noinst_LTLIBRARIES=$(testutils_noisnt_libraries)
assert_equals_uint64 (_START (trackelement), 0);
assert_equals_uint64 (_DURATION (trackelement), 5);
- /* Check no gap were wrongly added */
- assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 1);
+ /* Check no gap were wrongly added
+ * 2: 1 for the trackelement and 1 for the mixer */
+ assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 2);
clip1 = GES_CLIP (ges_test_clip_new ());
fail_unless (clip1 != NULL);
assert_equals_uint64 (_DURATION (trackelement1), 5);
/* Check the gap as properly been added */
- assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 3);
+ assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 4);
for (tmp = GST_BIN_CHILDREN (composition); tmp; tmp = tmp->next) {
+ guint prio;
GstElement *tmp_gnlobj = GST_ELEMENT (tmp->data);
- if (tmp_gnlobj != gnlsrc && tmp_gnlobj != gnlsrc1) {
+ g_object_get (tmp_gnlobj, "priority", &prio, NULL);
+ if (tmp_gnlobj != gnlsrc && tmp_gnlobj != gnlsrc1 && prio == 1) {
gap = tmp_gnlobj;
}
}
fail_unless (gap != NULL);
fail_unless (ges_timeline_commit (timeline));
- gap_object_check (gap, 5, 10, 0);
+ gap_object_check (gap, 5, 10, 1);
clip2 = GES_CLIP (ges_test_clip_new ());
fail_unless (clip2 != NULL);
fail_unless (ges_track_element_get_track (trackelement2) == track);
assert_equals_uint64 (_START (trackelement2), 35);
assert_equals_uint64 (_DURATION (trackelement2), 5);
- assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 5);
+ assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 6);
gst_object_unref (timeline);
}
ges_init ();
- track = GES_TRACK(ges_audio_track_new ());
+ track = GES_TRACK (ges_audio_track_new ());
layer = ges_layer_new ();
timeline = ges_timeline_new ();
fail_unless (timeline != NULL);
fail_unless (ges_timeline_add_layer (timeline, layer));
fail_unless (ges_timeline_add_track (timeline, track));
- fail_unless (ges_timeline_add_track (timeline, GES_TRACK(ges_video_track_new ())));
+ fail_unless (ges_timeline_add_track (timeline,
+ GES_TRACK (ges_video_track_new ())));
/* Set some properties */
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
/* Check that a gap was properly added */
composition = find_composition (track);
- assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 1);
+ /* We also have an adder in that composition */
+ assert_equals_int (g_list_length (GST_BIN_CHILDREN (composition)), 2);
gap = GST_BIN_CHILDREN (composition)->data;
fail_unless (gap != NULL);
fail_unless (ges_timeline_commit (timeline));
- gap_object_check (gap, 0, 10, 0);
+ gap_object_check (gap, 0, 10, 1);
gst_object_unref (timeline);
}
ges_init ();
timeline = ges_timeline_new ();
- layer = (GESLayer *) ges_simple_layer_new ();
+ layer = (GESLayer *) ges_layer_new ();
track_video = GES_TRACK (ges_video_track_new ());
ges_timeline_add_track (timeline, track_video);
assert_equals_int (prio3, LAYER_HEIGHT * 3 - 1 + MIN_GNL_PRIO);
/* And change TrackElement-s priorities and check that changes are not
- * refected on it containing Clip */
- ges_timeline_element_set_priority (GES_TIMELINE_ELEMENT (trackelement3),
- LAYER_HEIGHT * 2);
- ges_timeline_commit (timeline);
- g_object_get (gnlobj3, "priority", &prio3, NULL);
- assert_equals_int (prio3, 2 * LAYER_HEIGHT);
- assert_equals_int (_PRIORITY (clip3), LAYER_HEIGHT - 1);
+ * refected on it containing Clip
+ * FIXME : We should rework the way we handle the case were a trackobject
+ * prio is set outside the layer it is in.
+ * ges_timeline_element_set_priority (GES_TIMELINE_ELEMENT (trackelement3),
+ * ges_timeline_commit (timeline);
+ * LAYER_HEIGHT * 2);
+ * g_object_get (gnlobj3, "priority", &prio3, NULL);
+ * assert_equals_int (prio3, 2 * LAYER_HEIGHT);
+ * assert_equals_int (_PRIORITY (clip3), LAYER_HEIGHT - 1); */
gst_object_unref (trackelement1);
gst_object_unref (trackelement2);
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gst-editing-services
+ *
+ * Copyright (C) 2013 Thibault Saunier <tsaunier@gnome.org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.";
+ *
+ */
+#include "test-utils.h"
+#include <ges/ges.h>
+#include <gst/check/gstcheck.h>
+
+#include <ges/ges-smart-adder.h>
+
+static GMainLoop *main_loop;
+
+GST_START_TEST (simple_smart_adder_test)
+{
+ GstPad *requested_pad;
+ GstPadTemplate *template = NULL;
+ GESTrack *track = GES_TRACK (ges_audio_track_new ());
+ GstElement *smart_adder = ges_smart_adder_new (track);
+
+ fail_unless (GES_IS_SMART_ADDER (smart_adder));
+ fail_unless (GST_IS_ELEMENT (smart_adder));
+ fail_unless (GST_IS_ELEMENT (GES_SMART_ADDER (smart_adder)->adder));
+ fail_unless (GST_IS_PAD (GES_SMART_ADDER (smart_adder)->srcpad));
+
+ template =
+ gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (smart_adder),
+ "sink_%u");
+ fail_unless (template != NULL);
+ requested_pad = gst_element_request_pad (GST_ELEMENT (smart_adder),
+ template, NULL, NULL);
+ fail_unless (GST_IS_PAD (requested_pad));
+
+ gst_object_unref (smart_adder);
+ gst_object_unref (track);
+}
+
+GST_END_TEST;
+
+static void
+message_received_cb (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
+{
+ GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+ GST_MESSAGE_SRC (message), message);
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_EOS:
+ /* we should check if we really finished here */
+ GST_WARNING ("Got an EOS");
+ g_main_loop_quit (main_loop);
+ break;
+ case GST_MESSAGE_SEGMENT_START:
+ case GST_MESSAGE_SEGMENT_DONE:
+ /* We shouldn't see any segement messages, since we didn't do a segment seek */
+ GST_WARNING ("Saw a Segment start/stop");
+ fail_if (TRUE);
+ g_main_loop_quit (main_loop);
+ break;
+ case GST_MESSAGE_ERROR:
+ fail_error_message (message);
+ g_main_loop_quit (main_loop);
+ default:
+ break;
+ }
+}
+
+GST_START_TEST (simple_audio_mixed_with_pipeline)
+{
+ GstBus *bus;
+ GESAsset *asset;
+ GESClip *tmpclip;
+ GstMessage *message;
+ GESLayer *layer, *layer1;
+ GESTrack *track = GES_TRACK (ges_audio_track_new ());
+ GESTimeline *timeline = ges_timeline_new ();
+ GESTimelinePipeline *pipeline = ges_test_create_pipeline (timeline);
+
+ ges_timeline_add_track (timeline, track);
+ layer = ges_timeline_append_layer (timeline);
+ layer1 = ges_timeline_append_layer (timeline);
+
+ asset = GES_ASSET (ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL));
+
+ GST_DEBUG ("Setting volume on the layer");
+ ges_meta_container_set_float (GES_META_CONTAINER (layer), GES_META_VOLUME,
+ 1.5);
+
+ tmpclip = ges_layer_add_asset (layer, asset, 0, 0, 1 * GST_SECOND,
+ GES_TRACK_TYPE_AUDIO);
+ ges_audio_test_source_set_volume (GES_CONTAINER_CHILDREN (tmpclip)->data,
+ 1.0);
+ ges_audio_test_source_set_freq (GES_CONTAINER_CHILDREN (tmpclip)->data, 550);
+
+ tmpclip = ges_layer_add_asset (layer1, asset, 0, 0, 2 * GST_SECOND,
+ GES_TRACK_TYPE_AUDIO);
+
+ ges_audio_test_source_set_volume (GES_CONTAINER_CHILDREN (tmpclip)->data, 1);
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+ g_signal_connect (bus, "message", (GCallback) message_received_cb, pipeline);
+ fail_if (gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING)
+ == GST_STATE_CHANGE_FAILURE);
+ message = gst_bus_timed_pop_filtered (bus, 5 * GST_SECOND,
+ GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR);
+
+ if (message == NULL) {
+ fail_unless ("No message after 5 seconds" == NULL);
+ goto done;
+ } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR)
+ fail_error_message (message);
+
+ GST_INFO ("running main loop");
+ g_main_loop_run (main_loop);
+ g_main_loop_unref (main_loop);
+
+done:
+ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
+ gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+
+static Suite *
+ges_suite (void)
+{
+ Suite *s = suite_create ("Smart mixers");
+ TCase *tc_chain = tcase_create ("smart-mixers");
+
+ suite_add_tcase (s, tc_chain);
+
+ tcase_add_test (tc_chain, simple_smart_adder_test);
+ tcase_add_test (tc_chain, simple_audio_mixed_with_pipeline);
+
+ return s;
+}
+
+int
+main (int argc, char **argv)
+{
+ int nf;
+
+ Suite *s = ges_suite ();
+ SRunner *sr = srunner_create (s);
+
+ gst_check_init (&argc, &argv);
+ ges_init ();
+
+ srunner_run_all (sr, CK_NORMAL);
+ nf = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return nf;
+}