2 * empathy-gst-video-src.c - Source for EmpathyGstVideoSrc
3 * Copyright (C) 2008 Collabora Ltd.
4 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <gst/interfaces/colorbalance.h>
27 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
28 #include <libempathy/empathy-debug.h>
30 #include "empathy-video-src.h"
32 G_DEFINE_TYPE(EmpathyGstVideoSrc, empathy_video_src, GST_TYPE_BIN)
34 /* Keep in sync with EmpathyGstVideoSrcChannel */
35 static const gchar *channel_names[NR_EMPATHY_GST_VIDEO_SRC_CHANNELS] = {
36 "contrast", "brightness", "gamma" };
45 static guint signals[LAST_SIGNAL] = {0};
48 /* private structure */
49 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate;
51 struct _EmpathyGstVideoSrcPrivate
53 gboolean dispose_has_run;
55 /* Element implementing a ColorBalance interface */
57 /* Element for resolution and framerate adjustment */
58 GstElement *capsfilter;
64 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
65 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
66 EmpathyGstVideoSrcPrivate))
68 * empathy_gst_add_to_bin - create a new gst element, add to bin and link it.
69 * @bin - bin to add the new element to.
70 * @src - src element for the new element (may be NULL).
71 * @name - name of the factory for the new element
73 * Returns: The newly created element ot %NULL on failure
76 empathy_gst_add_to_bin (GstBin *bin,
78 const gchar *factoryname)
82 if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
84 g_message ("Element factory \"%s\" not found.", factoryname);
88 if (!gst_bin_add (bin, ret))
90 g_warning ("Couldn't add \"%s\" to bin.", factoryname);
94 /* do not link if src == NULL, just exit here */
98 if (!gst_element_link (src, ret))
100 g_warning ("Failed to link \"%s\".", factoryname);
101 gst_bin_remove (bin, ret);
109 gst_object_unref (ret);
115 empathy_video_src_init (EmpathyGstVideoSrc *obj)
117 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
118 GstElement *element, *element_back;
123 /* allocate caps here, so we can update it by optional elements */
124 caps = gst_caps_new_simple ("video/x-raw-yuv",
125 "width", G_TYPE_INT, 320,
126 "height", G_TYPE_INT, 240,
129 /* allocate any data required by the object here */
130 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
131 NULL, "v4l2src")) == NULL)
132 g_error ("Couldn't add \"v4l2src\" (gst-plugins-good missing?)");
134 /* we need to save our source to priv->src */
137 /* videomaxrate is optional as it's part of gst-plugins-bad. So don't
138 * fail if it doesn't exist. */
139 element_back = element;
140 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
141 element, "videomaxrate")) == NULL)
143 g_message ("Couldn't add \"videomaxrate\" (gst-plugins-bad missing?)");
144 element = element_back;
148 gst_caps_set_simple (caps,
149 "framerate", GST_TYPE_FRACTION, 15, 1,
153 str = gst_caps_to_string (caps);
154 DEBUG ("Current video src caps are : %s", str);
157 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
158 element, "ffmpegcolorspace")) == NULL)
159 g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
161 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
162 element, "videoscale")) == NULL)
163 g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
165 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
166 element, "capsfilter")) == NULL)
168 "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
170 priv->capsfilter = element;
171 g_object_set (G_OBJECT (element), "caps", caps, NULL);
174 /* optionally add postproc_tmpnoise to improve the performance of encoders */
175 element_back = element;
176 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
177 element, "postproc_tmpnoise")) == NULL)
179 g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
180 element = element_back;
183 src = gst_element_get_static_pad (element, "src");
184 g_assert (src != NULL);
186 ghost = gst_ghost_pad_new ("src", src);
188 g_error ("Unable to create ghost pad for the videosrc");
190 if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
191 g_error ("pad with the same name already existed or "
192 "the pad already had another parent.");
194 gst_object_unref (G_OBJECT (src));
197 static void empathy_video_src_dispose (GObject *object);
198 static void empathy_video_src_finalize (GObject *object);
201 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
203 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
205 g_type_class_add_private (empathy_video_src_class,
206 sizeof (EmpathyGstVideoSrcPrivate));
208 object_class->dispose = empathy_video_src_dispose;
209 object_class->finalize = empathy_video_src_finalize;
213 empathy_video_src_dispose (GObject *object)
215 EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
216 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
218 if (priv->dispose_has_run)
221 priv->dispose_has_run = TRUE;
223 /* release any references held by the object here */
225 if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
226 G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
230 empathy_video_src_finalize (GObject *object)
232 //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
233 //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
235 /* free any data held directly by the object here */
237 G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
241 empathy_video_src_new (void)
243 static gboolean registered = FALSE;
246 if (!gst_element_register (NULL, "empathyvideosrc",
247 GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
251 return gst_element_factory_make ("empathyvideosrc", NULL);
254 static GstColorBalance *
255 dup_color_balance (GstElement *src)
259 /* Find something supporting GstColorBalance */
260 color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
265 /* colorbalance is wrapped by GstImplementsInterface, we
266 * need to check if it is actually supported for this instance
267 * in its current state before trying to use it */
268 if (!GST_IS_COLOR_BALANCE (color))
270 g_object_unref (color);
274 return GST_COLOR_BALANCE (color);
278 empathy_video_src_set_channel (GstElement *src,
279 EmpathyGstVideoSrcChannel channel, guint percent)
281 GstColorBalance *balance;
282 const GList *channels;
285 balance = dup_color_balance (src);
289 channels = gst_color_balance_list_channels (balance);
291 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
293 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
295 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
297 gst_color_balance_set_value (balance, c,
298 ((c->max_value - c->min_value) * percent)/100
304 g_object_unref (balance);
308 empathy_video_src_get_channel (GstElement *src,
309 EmpathyGstVideoSrcChannel channel)
311 GstColorBalance *balance;
312 const GList *channels;
316 balance = dup_color_balance (src);
320 channels = gst_color_balance_list_channels (balance);
322 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
324 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
326 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
329 ((gst_color_balance_get_value (balance, c)
330 - c->min_value) * 100) /
331 (c->max_value - c->min_value);
337 g_object_unref (balance);
344 empathy_video_src_get_supported_channels (GstElement *src)
346 GstColorBalance *balance;
347 const GList *channels;
351 balance = dup_color_balance (src);
355 channels = gst_color_balance_list_channels (balance);
357 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
359 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
362 for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
364 if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
372 g_object_unref (balance);
379 empathy_video_src_change_device (EmpathyGstVideoSrc *self,
382 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
385 gst_element_get_state (priv->src, &state, NULL, 0);
387 g_return_if_fail (state == GST_STATE_NULL);
389 g_object_set (priv->src, "device", device, NULL);
393 empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
395 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
398 g_object_get (priv->src, "device", &device, NULL);
404 empathy_video_src_set_framerate (GstElement *src,
407 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
410 g_return_if_fail (priv->capsfilter != NULL);
412 g_object_get (priv->capsfilter, "caps", &caps, NULL);
413 caps = gst_caps_make_writable (caps);
415 gst_caps_set_simple (caps,
416 "framerate", GST_TYPE_FRACTION, framerate, 1,
419 g_object_set (priv->capsfilter, "caps", caps, NULL);
423 empathy_video_src_set_resolution (GstElement *src,
427 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
431 g_return_if_fail (priv->capsfilter != NULL);
433 gst_element_set_locked_state (priv->src, TRUE);
434 gst_element_set_state (priv->src, GST_STATE_NULL);
436 g_object_get (priv->capsfilter, "caps", &caps, NULL);
437 caps = gst_caps_make_writable (caps);
439 gst_caps_set_simple (caps,
440 "width", G_TYPE_INT, width,
441 "height", G_TYPE_INT, height,
444 g_object_set (priv->capsfilter, "caps", caps, NULL);
446 /* Reset clock an base time, this is require for videotestsrc and hopefully
447 * has no side effect */
448 gst_clock = gst_element_get_clock (src);
449 gst_element_set_clock (priv->src, gst_clock);
450 gst_element_set_base_time (priv->src, gst_element_get_base_time (src));
451 gst_object_unref (gst_clock);
453 gst_element_set_locked_state (priv->src, FALSE);
454 gst_element_sync_state_with_parent (priv->src);