mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 20:05:38 +00:00
smart-adder: Implement a GESSmartAdder bin element to be used as mixing element
..in audio tracks
This commit is contained in:
parent
b87c800743
commit
724a6c1bb5
11 changed files with 600 additions and 49 deletions
|
@ -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 = \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
|
|
|
@ -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
290
ges/ges-smart-adder.c
Normal 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
63
ges/ges-smart-adder.h
Normal 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_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,6 +40,7 @@ check_PROGRAMS = \
|
|||
ges/transition \
|
||||
ges/overlays\
|
||||
ges/text_properties\
|
||||
ges/mixers\
|
||||
ges/project
|
||||
|
||||
noinst_LTLIBRARIES=$(testutils_noisnt_libraries)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
171
tests/check/ges/mixers.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue