1 /* GStreamer Editing Services
2 * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
3 * 2010 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:gesaudiotransition
23 * @title: GESAudioTransition
24 * @short_description: implements audio crossfade transition
30 #include "ges-internal.h"
31 #include "ges-track-element.h"
32 #include "ges-audio-transition.h"
34 #include <gst/controller/gstdirectcontrolbinding.h>
36 struct _GESAudioTransitionPrivate
38 /* these enable volume interpolation. Unlike video, both inputs are adjusted
40 GstControlSource *a_control_source;
42 GstControlSource *b_control_source;
51 G_DEFINE_TYPE_WITH_PRIVATE (GESAudioTransition, ges_audio_transition,
54 #define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
57 ges_audio_transition_duration_changed (GESTrackElement * self, guint64);
59 static GstElement *ges_audio_transition_create_element (GESTrackElement * self);
61 static void ges_audio_transition_dispose (GObject * object);
63 static void ges_audio_transition_finalize (GObject * object);
65 static void ges_audio_transition_get_property (GObject * object, guint
66 property_id, GValue * value, GParamSpec * pspec);
68 static void ges_audio_transition_set_property (GObject * object, guint
69 property_id, const GValue * value, GParamSpec * pspec);
72 duration_changed_cb (GESTrackElement * self, GParamSpec * arg G_GNUC_UNUSED)
74 ges_audio_transition_duration_changed (self,
75 ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (self)));
79 ges_audio_transition_class_init (GESAudioTransitionClass * klass)
81 GObjectClass *object_class;
82 GESTrackElementClass *toclass;
84 object_class = G_OBJECT_CLASS (klass);
85 toclass = GES_TRACK_ELEMENT_CLASS (klass);
87 object_class->get_property = ges_audio_transition_get_property;
88 object_class->set_property = ges_audio_transition_set_property;
89 object_class->dispose = ges_audio_transition_dispose;
90 object_class->finalize = ges_audio_transition_finalize;
92 toclass->create_element = ges_audio_transition_create_element;
93 toclass->ABI.abi.default_track_type = GES_TRACK_TYPE_AUDIO;
98 ges_audio_transition_init (GESAudioTransition * self)
101 self->priv = ges_audio_transition_get_instance_private (self);
105 ges_audio_transition_dispose (GObject * object)
107 GESAudioTransition *self;
109 self = GES_AUDIO_TRANSITION (object);
111 if (self->priv->a_control_source) {
112 if (self->priv->a_control_source)
113 gst_object_unref (self->priv->a_control_source);
114 self->priv->a_control_source = NULL;
117 if (self->priv->b_control_source) {
118 if (self->priv->b_control_source)
119 gst_object_unref (self->priv->b_control_source);
120 self->priv->b_control_source = NULL;
123 g_signal_handlers_disconnect_by_func (GES_TRACK_ELEMENT (self),
124 duration_changed_cb, NULL);
126 G_OBJECT_CLASS (ges_audio_transition_parent_class)->dispose (object);
130 ges_audio_transition_finalize (GObject * object)
132 G_OBJECT_CLASS (ges_audio_transition_parent_class)->finalize (object);
136 ges_audio_transition_get_property (GObject * object,
137 guint property_id, GValue * value, GParamSpec * pspec)
139 switch (property_id) {
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
146 ges_audio_transition_set_property (GObject * object,
147 guint property_id, const GValue * value, GParamSpec * pspec)
149 switch (property_id) {
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
156 link_element_to_mixer_with_volume (GstBin * bin, GstElement * element,
159 GstElement *volume = gst_element_factory_make ("volume", NULL);
160 GstElement *resample = gst_element_factory_make ("audioresample", NULL);
162 gst_bin_add (bin, volume);
163 gst_bin_add (bin, resample);
165 if (!fast_element_link (element, volume) ||
166 !fast_element_link (volume, resample) ||
167 !gst_element_link_pads_full (resample, "src", mixer, "sink_%u",
168 GST_PAD_LINK_CHECK_NOTHING))
169 GST_ERROR_OBJECT (bin, "Error linking volume to mixer");
171 return G_OBJECT (volume);
175 ges_audio_transition_create_element (GESTrackElement * track_element)
177 GESAudioTransition *self;
178 GstElement *topbin, *iconva, *iconvb, *oconv;
179 GObject *atarget, *btarget = NULL;
180 const gchar *propname = "volume";
181 GstElement *mixer = NULL;
182 GstPad *sinka_target, *sinkb_target, *src_target, *sinka, *sinkb, *src;
184 GstControlSource *acontrol_source, *bcontrol_source;
186 self = GES_AUDIO_TRANSITION (track_element);
188 GST_LOG ("creating an audio bin");
190 topbin = gst_bin_new ("transition-bin");
191 iconva = gst_element_factory_make ("audioconvert", "tr-aconv-a");
192 iconvb = gst_element_factory_make ("audioconvert", "tr-aconv-b");
193 oconv = gst_element_factory_make ("audioconvert", "tr-aconv-output");
195 gst_bin_add_many (GST_BIN (topbin), iconva, iconvb, oconv, NULL);
197 mixer = gst_element_factory_make ("audiomixer", NULL);
198 gst_bin_add (GST_BIN (topbin), mixer);
200 atarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconva, mixer);
201 btarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconvb, mixer);
203 g_assert (atarget && btarget);
205 fast_element_link (mixer, oconv);
207 sinka_target = gst_element_get_static_pad (iconva, "sink");
208 sinkb_target = gst_element_get_static_pad (iconvb, "sink");
209 src_target = gst_element_get_static_pad (oconv, "src");
211 sinka = gst_ghost_pad_new ("sinka", sinka_target);
212 sinkb = gst_ghost_pad_new ("sinkb", sinkb_target);
213 src = gst_ghost_pad_new ("src", src_target);
215 gst_element_add_pad (topbin, src);
216 gst_element_add_pad (topbin, sinka);
217 gst_element_add_pad (topbin, sinkb);
219 /* set up interpolation */
221 gst_object_unref (sinka_target);
222 gst_object_unref (sinkb_target);
223 gst_object_unref (src_target);
225 acontrol_source = gst_interpolation_control_source_new ();
226 g_object_set (acontrol_source, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
228 bcontrol_source = gst_interpolation_control_source_new ();
229 g_object_set (bcontrol_source, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
231 self->priv->a_control_source = acontrol_source;
232 self->priv->b_control_source = bcontrol_source;
235 ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (track_element));
236 ges_audio_transition_duration_changed (track_element, duration);
238 g_signal_connect (track_element, "notify::duration",
239 G_CALLBACK (duration_changed_cb), NULL);
241 gst_object_add_control_binding (GST_OBJECT (atarget),
242 gst_direct_control_binding_new (GST_OBJECT (atarget), propname,
244 gst_object_add_control_binding (GST_OBJECT (btarget),
245 gst_direct_control_binding_new (GST_OBJECT (btarget), propname,
248 self->priv->a_control_source = acontrol_source;
249 self->priv->b_control_source = bcontrol_source;
255 ges_audio_transition_duration_changed (GESTrackElement * track_element,
258 GESAudioTransition *self;
259 GstElement *nleobj = ges_track_element_get_nleobject (track_element);
260 GstTimedValueControlSource *ta, *tb;
262 self = GES_AUDIO_TRANSITION (track_element);
264 GST_INFO ("updating controller: nleobj (%p)", nleobj);
266 if (G_UNLIKELY ((!self->priv->a_control_source ||
267 !self->priv->b_control_source)))
270 GST_INFO ("setting values on controller");
271 ta = GST_TIMED_VALUE_CONTROL_SOURCE (self->priv->a_control_source);
272 tb = GST_TIMED_VALUE_CONTROL_SOURCE (self->priv->b_control_source);
274 gst_timed_value_control_source_unset_all (ta);
275 gst_timed_value_control_source_unset_all (tb);
276 /* The volume property goes from 0 to 10, so we want to interpolate between
278 gst_timed_value_control_source_set (ta, 0, 0.1);
279 gst_timed_value_control_source_set (ta, duration, 0.0);
281 gst_timed_value_control_source_set (tb, 0, 0.0);
282 gst_timed_value_control_source_set (tb, duration, 0.1);
284 GST_INFO ("done updating controller");
288 * ges_audio_transition_new:
290 * Creates a new #GESAudioTransition.
292 * Returns: (transfer floating): The newly created #GESAudioTransition.
294 * Deprecated: 1.18: This should never be called by applications as this will
295 * be created by clips.
298 ges_audio_transition_new (void)
300 GESAudioTransition *res;
301 GESAsset *asset = ges_asset_request (GES_TYPE_AUDIO_TRANSITION, NULL, NULL);
303 res = GES_AUDIO_TRANSITION (ges_asset_extract (asset, NULL));
304 gst_object_unref (asset);