smart-adder: Implement a GESSmartAdder bin element to be used as mixing element

..in audio tracks
This commit is contained in:
Thibault Saunier 2013-03-31 00:08:15 +01:00
parent b87c800743
commit 724a6c1bb5
11 changed files with 600 additions and 49 deletions

View file

@ -61,6 +61,7 @@ libges_@GST_API_VERSION@_la_SOURCES = \
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/
@ -119,6 +120,7 @@ libges_@GST_API_VERSION@include_HEADERS = \
ges-timeline-element.h \
ges-container.h \
ges-effect-asset.h \
ges-smart-adder.h \
ges-utils.h
noinst_HEADERS = \

View file

@ -22,10 +22,11 @@
* @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;
@ -77,6 +78,8 @@ ges_audio_track_class_init (GESAudioTrackClass * klass)
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;
}
/****************************************************

View file

@ -39,13 +39,19 @@ typedef struct _GESAudioTrackPrivate GESAudioTrackPrivate;
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;

290
ges/ges-smart-adder.c Normal file
View file

@ -0,0 +1,290 @@
/* -*- 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);
}

63
ges/ges-smart-adder.h Normal file
View file

@ -0,0 +1,63 @@
/* -*- 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_ */

View file

@ -434,6 +434,42 @@ ges_track_finalize (GObject * object)
G_OBJECT_CLASS (ges_track_parent_class)->finalize (object);
}
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)
{
@ -445,6 +481,7 @@ ges_track_class_init (GESTrackClass * 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:
@ -541,35 +578,6 @@ ges_track_init (GESTrack * self)
(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;
}
}
}
/**

View file

@ -40,6 +40,7 @@ check_PROGRAMS = \
ges/transition \
ges/overlays\
ges/text_properties\
ges/mixers\
ges/project
noinst_LTLIBRARIES=$(testutils_noisnt_libraries)

View file

@ -293,8 +293,9 @@ GST_START_TEST (test_gap_filling_basic)
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);
@ -316,18 +317,20 @@ GST_START_TEST (test_gap_filling_basic)
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);
@ -339,7 +342,7 @@ GST_START_TEST (test_gap_filling_basic)
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);
}
@ -358,14 +361,15 @@ GST_START_TEST (test_gap_filling_empty_track)
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);
@ -377,12 +381,13 @@ GST_START_TEST (test_gap_filling_empty_track)
/* 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);
}

View file

@ -97,7 +97,7 @@ GST_START_TEST (test_get_effects_from_tl)
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);

View file

@ -265,13 +265,15 @@ GST_START_TEST (test_layer_priorities)
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);

171
tests/check/ges/mixers.c Normal file
View file

@ -0,0 +1,171 @@
/* -*- 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;
}