Branch data Line data Source code
1 : : /* GStreamer Editing Services
2 : : * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
3 : : * 2010 Nokia Corporation
4 : : *
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.
9 : : *
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.
14 : : *
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., 59 Temple Place - Suite 330,
18 : : * Boston, MA 02111-1307, USA.
19 : : */
20 : :
21 : : /**
22 : : * SECTION:ges-track-audio-transition
23 : : * @short_description: implements audio crossfade transition
24 : : */
25 : :
26 : : #include "ges-internal.h"
27 : : #include "ges-track-object.h"
28 : : #include "ges-track-audio-transition.h"
29 : :
30 [ + + ]: 43 : G_DEFINE_TYPE (GESTrackAudioTransition, ges_track_audio_transition,
31 : 43 : GES_TYPE_TRACK_TRANSITION);
32 : :
33 : : struct _GESTrackAudioTransitionPrivate
34 : : {
35 : : /* these enable volume interpolation. Unlike video, both inputs are adjusted
36 : : * simultaneously */
37 : : GstController *a_controller;
38 : : GstInterpolationControlSource *a_control_source;
39 : :
40 : : GstController *b_controller;
41 : : GstInterpolationControlSource *b_control_source;
42 : :
43 : : };
44 : :
45 : : enum
46 : : {
47 : : PROP_0,
48 : : };
49 : :
50 : :
51 : : #define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
52 : :
53 : : static void
54 : : ges_track_audio_transition_duration_changed (GESTrackObject * self, guint64);
55 : :
56 : : static GstElement *ges_track_audio_transition_create_element (GESTrackObject
57 : : * self);
58 : :
59 : : static void ges_track_audio_transition_dispose (GObject * object);
60 : :
61 : : static void ges_track_audio_transition_finalize (GObject * object);
62 : :
63 : : static void ges_track_audio_transition_get_property (GObject * object, guint
64 : : property_id, GValue * value, GParamSpec * pspec);
65 : :
66 : : static void ges_track_audio_transition_set_property (GObject * object, guint
67 : : property_id, const GValue * value, GParamSpec * pspec);
68 : :
69 : : static void
70 : 3 : ges_track_audio_transition_class_init (GESTrackAudioTransitionClass * klass)
71 : : {
72 : : GObjectClass *object_class;
73 : : GESTrackObjectClass *toclass;
74 : :
75 : 3 : g_type_class_add_private (klass, sizeof (GESTrackAudioTransitionPrivate));
76 : :
77 : 3 : object_class = G_OBJECT_CLASS (klass);
78 : 3 : toclass = GES_TRACK_OBJECT_CLASS (klass);
79 : :
80 : 3 : object_class->get_property = ges_track_audio_transition_get_property;
81 : 3 : object_class->set_property = ges_track_audio_transition_set_property;
82 : 3 : object_class->dispose = ges_track_audio_transition_dispose;
83 : 3 : object_class->finalize = ges_track_audio_transition_finalize;
84 : :
85 : 3 : toclass->duration_changed = ges_track_audio_transition_duration_changed;
86 : :
87 : 3 : toclass->create_element = ges_track_audio_transition_create_element;
88 : :
89 : 3 : }
90 : :
91 : : static void
92 : 8 : ges_track_audio_transition_init (GESTrackAudioTransition * self)
93 : : {
94 : :
95 : 8 : self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
96 : : GES_TYPE_TRACK_AUDIO_TRANSITION, GESTrackAudioTransitionPrivate);
97 : :
98 : 8 : self->priv->a_controller = NULL;
99 : 8 : self->priv->a_control_source = NULL;
100 : :
101 : 8 : self->priv->b_controller = NULL;
102 : 8 : self->priv->b_control_source = NULL;
103 : 8 : }
104 : :
105 : : static void
106 : 8 : ges_track_audio_transition_dispose (GObject * object)
107 : : {
108 : : GESTrackAudioTransition *self;
109 : :
110 : 8 : self = GES_TRACK_AUDIO_TRANSITION (object);
111 : :
112 [ + - ]: 8 : if (self->priv->a_controller) {
113 : 8 : g_object_unref (self->priv->a_controller);
114 : 8 : self->priv->a_controller = NULL;
115 [ + - ]: 8 : if (self->priv->a_control_source)
116 : 8 : gst_object_unref (self->priv->a_control_source);
117 : 8 : self->priv->a_control_source = NULL;
118 : : }
119 : :
120 [ + - ]: 8 : if (self->priv->b_controller) {
121 : 8 : g_object_unref (self->priv->b_controller);
122 : 8 : self->priv->b_controller = NULL;
123 [ + - ]: 8 : if (self->priv->b_control_source)
124 : 8 : gst_object_unref (self->priv->b_control_source);
125 : 8 : self->priv->b_control_source = NULL;
126 : : }
127 : :
128 : 8 : G_OBJECT_CLASS (ges_track_audio_transition_parent_class)->dispose (object);
129 : 8 : }
130 : :
131 : : static void
132 : 8 : ges_track_audio_transition_finalize (GObject * object)
133 : : {
134 : 8 : G_OBJECT_CLASS (ges_track_audio_transition_parent_class)->finalize (object);
135 : 8 : }
136 : :
137 : : static void
138 : 0 : ges_track_audio_transition_get_property (GObject * object,
139 : : guint property_id, GValue * value, GParamSpec * pspec)
140 : : {
141 : : switch (property_id) {
142 : : default:
143 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144 : : }
145 : 0 : }
146 : :
147 : : static void
148 : 0 : ges_track_audio_transition_set_property (GObject * object,
149 : : guint property_id, const GValue * value, GParamSpec * pspec)
150 : : {
151 : : switch (property_id) {
152 : : default:
153 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154 : : }
155 : 0 : }
156 : :
157 : : static GObject *
158 : 16 : link_element_to_mixer_with_volume (GstBin * bin, GstElement * element,
159 : : GstElement * mixer)
160 : : {
161 : 16 : GstElement *volume = gst_element_factory_make ("volume", NULL);
162 : 16 : gst_bin_add (bin, volume);
163 : :
164 [ + - - + ]: 32 : if (!fast_element_link (element, volume) ||
165 : 16 : !gst_element_link_pads_full (volume, "src", mixer, "sink%d",
166 : : GST_PAD_LINK_CHECK_NOTHING))
167 [ # # ]: 0 : GST_ERROR_OBJECT (bin, "Error linking volume to mixer");
168 : :
169 : 16 : return G_OBJECT (volume);
170 : : }
171 : :
172 : : static GstElement *
173 : 8 : ges_track_audio_transition_create_element (GESTrackObject * object)
174 : : {
175 : : GESTrackAudioTransition *self;
176 : : GstElement *topbin, *iconva, *iconvb, *oconv;
177 : 8 : GObject *atarget, *btarget = NULL;
178 : 8 : const gchar *propname = "volume";
179 : 8 : GstElement *mixer = NULL;
180 : : GstPad *sinka_target, *sinkb_target, *src_target, *sinka, *sinkb, *src;
181 : : GstController *acontroller, *bcontroller;
182 : : GstInterpolationControlSource *acontrol_source, *bcontrol_source;
183 : :
184 : 8 : self = GES_TRACK_AUDIO_TRANSITION (object);
185 : :
186 : :
187 [ - + ]: 8 : GST_LOG ("creating an audio bin");
188 : :
189 : 8 : topbin = gst_bin_new ("transition-bin");
190 : 8 : iconva = gst_element_factory_make ("audioconvert", "tr-aconv-a");
191 : 8 : iconvb = gst_element_factory_make ("audioconvert", "tr-aconv-b");
192 : 8 : oconv = gst_element_factory_make ("audioconvert", "tr-aconv-output");
193 : :
194 : 8 : gst_bin_add_many (GST_BIN (topbin), iconva, iconvb, oconv, NULL);
195 : :
196 : 8 : mixer = gst_element_factory_make ("adder", NULL);
197 : 8 : gst_bin_add (GST_BIN (topbin), mixer);
198 : :
199 : 8 : atarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconva, mixer);
200 : 8 : btarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconvb, mixer);
201 : :
202 [ + - ][ + - ]: 8 : g_assert (atarget && btarget);
203 : :
204 : 8 : fast_element_link (mixer, oconv);
205 : :
206 : 8 : sinka_target = gst_element_get_static_pad (iconva, "sink");
207 : 8 : sinkb_target = gst_element_get_static_pad (iconvb, "sink");
208 : 8 : src_target = gst_element_get_static_pad (oconv, "src");
209 : :
210 : 8 : sinka = gst_ghost_pad_new ("sinka", sinka_target);
211 : 8 : sinkb = gst_ghost_pad_new ("sinkb", sinkb_target);
212 : 8 : src = gst_ghost_pad_new ("src", src_target);
213 : :
214 : 8 : gst_element_add_pad (topbin, src);
215 : 8 : gst_element_add_pad (topbin, sinka);
216 : 8 : gst_element_add_pad (topbin, sinkb);
217 : :
218 : : /* set up interpolation */
219 : :
220 : 8 : gst_object_unref (sinka_target);
221 : 8 : gst_object_unref (sinkb_target);
222 : 8 : gst_object_unref (src_target);
223 : :
224 : :
225 : : //g_object_set(atarget, propname, (gdouble) 0, NULL);
226 : : //g_object_set(btarget, propname, (gdouble) 0, NULL);
227 : :
228 : 8 : acontroller = gst_object_control_properties (atarget, propname, NULL);
229 : 8 : bcontroller = gst_object_control_properties (btarget, propname, NULL);
230 : :
231 [ + - ][ + - ]: 8 : g_assert (acontroller && bcontroller);
232 : :
233 : 8 : acontrol_source = gst_interpolation_control_source_new ();
234 : 8 : gst_controller_set_control_source (acontroller,
235 : 8 : propname, GST_CONTROL_SOURCE (acontrol_source));
236 : 8 : gst_interpolation_control_source_set_interpolation_mode (acontrol_source,
237 : : GST_INTERPOLATE_LINEAR);
238 : :
239 : 8 : bcontrol_source = gst_interpolation_control_source_new ();
240 : 8 : gst_controller_set_control_source (bcontroller,
241 : 8 : propname, GST_CONTROL_SOURCE (bcontrol_source));
242 : 8 : gst_interpolation_control_source_set_interpolation_mode (bcontrol_source,
243 : : GST_INTERPOLATE_LINEAR);
244 : :
245 : 8 : self->priv->a_controller = acontroller;
246 : 8 : self->priv->b_controller = bcontroller;
247 : 8 : self->priv->a_control_source = acontrol_source;
248 : 8 : self->priv->b_control_source = bcontrol_source;
249 : :
250 : 8 : return topbin;
251 : : }
252 : :
253 : : static void
254 : 8 : ges_track_audio_transition_duration_changed (GESTrackObject * object,
255 : : guint64 duration)
256 : : {
257 : : GESTrackAudioTransition *self;
258 : 8 : GstElement *gnlobj = ges_track_object_get_gnlobject (object);
259 : :
260 : 8 : GValue zero = { 0, };
261 : 8 : GValue one = { 0, };
262 : :
263 : 8 : self = GES_TRACK_AUDIO_TRANSITION (object);
264 : :
265 [ - + ]: 8 : GST_LOG ("updating controller: gnlobj (%p) acontroller(%p) bcontroller(%p)",
266 : : gnlobj, self->priv->a_controller, self->priv->b_controller);
267 : :
268 [ + - ][ + - ]: 8 : if (G_UNLIKELY ((!gnlobj || !self->priv->a_control_source ||
[ - + ]
269 : : !self->priv->b_control_source)))
270 : 8 : return;
271 : :
272 [ - + ]: 8 : GST_INFO ("duration: %" G_GUINT64_FORMAT, duration);
273 : 8 : g_value_init (&zero, G_TYPE_DOUBLE);
274 : 8 : g_value_init (&one, G_TYPE_DOUBLE);
275 : 8 : g_value_set_double (&zero, 0.0);
276 : 8 : g_value_set_double (&one, 1.0);
277 : :
278 [ - + ]: 8 : GST_LOG ("setting values on controller");
279 : :
280 : 8 : gst_interpolation_control_source_unset_all (self->priv->a_control_source);
281 : 8 : gst_interpolation_control_source_set (self->priv->a_control_source, 0, &one);
282 : 8 : gst_interpolation_control_source_set (self->priv->a_control_source,
283 : : duration, &zero);
284 : :
285 : 8 : gst_interpolation_control_source_unset_all (self->priv->b_control_source);
286 : 8 : gst_interpolation_control_source_set (self->priv->b_control_source, 0, &zero);
287 : 8 : gst_interpolation_control_source_set (self->priv->b_control_source, duration,
288 : : &one);
289 : :
290 [ - + ]: 8 : GST_LOG ("done updating controller");
291 : : }
292 : :
293 : : /**
294 : : * ges_track_audio_transition_new:
295 : : *
296 : : * Creates a new #GESTrackAudioTransition.
297 : : *
298 : : * Returns: The newly created #GESTrackAudioTransition.
299 : : */
300 : : GESTrackAudioTransition *
301 : 8 : ges_track_audio_transition_new (void)
302 : : {
303 : 8 : return g_object_new (GES_TYPE_TRACK_AUDIO_TRANSITION, NULL);
304 : : }
|