add missing config.h includes
[empathy-mirror.git] / src / empathy-video-src.c
blob8c9c7501548c6f6182d8845a72981717b58e5998
1 /*
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
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
26 #include <gst/interfaces/colorbalance.h>
28 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
29 #include <libempathy/empathy-debug.h>
31 #include "empathy-video-src.h"
33 G_DEFINE_TYPE(EmpathyGstVideoSrc, empathy_video_src, GST_TYPE_BIN)
35 /* Keep in sync with EmpathyGstVideoSrcChannel */
36 static const gchar *channel_names[NR_EMPATHY_GST_VIDEO_SRC_CHANNELS] = {
37 "contrast", "brightness", "gamma" };
39 /* signal enum */
40 #if 0
41 enum
43 LAST_SIGNAL
46 static guint signals[LAST_SIGNAL] = {0};
47 #endif
49 /* private structure */
50 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate;
52 struct _EmpathyGstVideoSrcPrivate
54 gboolean dispose_has_run;
55 GstElement *src;
56 /* Element implementing a ColorBalance interface */
57 GstElement *balance;
58 /* Elements for resolution and framerate adjustment */
59 GstElement *capsfilter;
60 GstElement *videorate;
61 guint width;
62 guint height;
63 guint framerate;
66 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
67 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
68 EmpathyGstVideoSrcPrivate))
69 /**
70 * empathy_gst_add_to_bin - create a new gst element, add to bin and link it.
71 * @bin - bin to add the new element to.
72 * @src - src element for the new element (may be NULL).
73 * @name - name of the factory for the new element
75 * Returns: The newly created element ot %NULL on failure
77 static GstElement *
78 empathy_gst_add_to_bin (GstBin *bin,
79 GstElement *src,
80 const gchar *factoryname)
82 GstElement *ret;
84 if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
86 g_message ("Element factory \"%s\" not found.", factoryname);
87 goto error;
90 if (!gst_bin_add (bin, ret))
92 g_warning ("Couldn't add \"%s\" to bin.", factoryname);
93 goto error;
96 /* do not link if src == NULL, just exit here */
97 if (src == NULL)
98 return ret;
100 if (!gst_element_link (src, ret))
102 g_warning ("Failed to link \"%s\".", factoryname);
103 gst_bin_remove (bin, ret);
104 goto error;
107 return ret;
109 error:
110 if (ret != NULL)
111 gst_object_unref (ret);
112 return NULL;
115 static gboolean
116 empathy_video_src_drop_eos (GstPad *pad, GstEvent *event, gpointer user_data)
118 return GST_EVENT_TYPE (event) != GST_EVENT_EOS;
121 static void
122 empathy_video_src_init (EmpathyGstVideoSrc *obj)
124 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
125 GstElement *element, *element_back;
126 GstPad *ghost, *src;
127 GstCaps *caps;
128 gchar *str;
130 /* allocate caps here, so we can update it by optional elements */
131 caps = gst_caps_new_simple ("video/x-raw-yuv",
132 "width", G_TYPE_INT, 320,
133 "height", G_TYPE_INT, 240,
134 NULL);
136 /* allocate any data required by the object here */
137 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
138 NULL, "v4l2src")) == NULL)
139 g_error ("Couldn't add \"v4l2src\" (gst-plugins-good missing?)");
141 /* we need to save our source to priv->src */
142 priv->src = element;
144 /* Drop EOS events, so that our sinks don't get confused when we restart the
145 * source (triggering an EOS) */
146 src = gst_element_get_static_pad (element, "src");
147 gst_pad_add_event_probe (src, G_CALLBACK (empathy_video_src_drop_eos), NULL);
148 gst_object_unref (src);
150 /* videorate with the required properties optional as it needs a currently
151 * unreleased gst-plugins-base 0.10.36 */
152 element_back = element;
153 element = empathy_gst_add_to_bin (GST_BIN (obj), element, "videorate");
155 if (element != NULL && g_object_class_find_property (
156 G_OBJECT_GET_CLASS (element), "max-rate") != NULL)
158 priv->videorate = element;
159 g_object_set (G_OBJECT (element),
160 "drop-only", TRUE,
161 "average-period", GST_SECOND/2,
162 NULL);
164 else
166 g_message ("videorate missing or doesn't have max-rate property, not"
167 "doing dynamic framerate changes (Needs gst-plugins-base >= 0.10.36)");
168 /* Refcount owned by the bin */
169 gst_bin_remove (GST_BIN (obj), element);
170 element = element_back;
173 gst_caps_set_simple (caps,
174 "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, 30, 1,
175 NULL);
177 str = gst_caps_to_string (caps);
178 DEBUG ("Current video src caps are : %s", str);
179 g_free (str);
181 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
182 element, "ffmpegcolorspace")) == NULL)
183 g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
185 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
186 element, "videoscale")) == NULL)
187 g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
189 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
190 element, "capsfilter")) == NULL)
191 g_error (
192 "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
194 priv->capsfilter = element;
195 g_object_set (G_OBJECT (element), "caps", caps, NULL);
198 /* optionally add postproc_tmpnoise to improve the performance of encoders */
199 element_back = element;
200 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
201 element, "postproc_tmpnoise")) == NULL)
203 g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
204 element = element_back;
207 src = gst_element_get_static_pad (element, "src");
208 g_assert (src != NULL);
210 ghost = gst_ghost_pad_new ("src", src);
211 if (ghost == NULL)
212 g_error ("Unable to create ghost pad for the videosrc");
214 if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
215 g_error ("pad with the same name already existed or "
216 "the pad already had another parent.");
218 gst_object_unref (G_OBJECT (src));
221 static void empathy_video_src_dispose (GObject *object);
222 static void empathy_video_src_finalize (GObject *object);
224 static void
225 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
227 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
229 g_type_class_add_private (empathy_video_src_class,
230 sizeof (EmpathyGstVideoSrcPrivate));
232 object_class->dispose = empathy_video_src_dispose;
233 object_class->finalize = empathy_video_src_finalize;
236 void
237 empathy_video_src_dispose (GObject *object)
239 EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
240 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
242 if (priv->dispose_has_run)
243 return;
245 priv->dispose_has_run = TRUE;
247 /* release any references held by the object here */
249 if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
250 G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
253 void
254 empathy_video_src_finalize (GObject *object)
256 //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
257 //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
259 /* free any data held directly by the object here */
261 G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
264 GstElement *
265 empathy_video_src_new (void)
267 static gboolean registered = FALSE;
269 if (!registered) {
270 if (!gst_element_register (NULL, "empathyvideosrc",
271 GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
272 return NULL;
273 registered = TRUE;
275 return gst_element_factory_make ("empathyvideosrc", NULL);
278 static GstColorBalance *
279 dup_color_balance (GstElement *src)
281 GstElement *color;
283 /* Find something supporting GstColorBalance */
284 color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
286 if (color == NULL)
287 return NULL;
289 /* colorbalance is wrapped by GstImplementsInterface, we
290 * need to check if it is actually supported for this instance
291 * in its current state before trying to use it */
292 if (!GST_IS_COLOR_BALANCE (color))
294 g_object_unref (color);
295 return NULL;
298 return GST_COLOR_BALANCE (color);
301 void
302 empathy_video_src_set_channel (GstElement *src,
303 EmpathyGstVideoSrcChannel channel, guint percent)
305 GstColorBalance *balance;
306 const GList *channels;
307 GList *l;
309 balance = dup_color_balance (src);
310 if (balance == NULL)
311 return;
313 channels = gst_color_balance_list_channels (balance);
315 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
317 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
319 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
321 gst_color_balance_set_value (balance, c,
322 ((c->max_value - c->min_value) * percent)/100
323 + c->min_value);
324 break;
328 g_object_unref (balance);
331 guint
332 empathy_video_src_get_channel (GstElement *src,
333 EmpathyGstVideoSrcChannel channel)
335 GstColorBalance *balance;
336 const GList *channels;
337 GList *l;
338 guint percent = 0;
340 balance = dup_color_balance (src);
341 if (balance == NULL)
342 return percent;
344 channels = gst_color_balance_list_channels (balance);
346 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
348 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
350 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
352 percent =
353 ((gst_color_balance_get_value (balance, c)
354 - c->min_value) * 100) /
355 (c->max_value - c->min_value);
357 break;
361 g_object_unref (balance);
363 return percent;
367 guint
368 empathy_video_src_get_supported_channels (GstElement *src)
370 GstColorBalance *balance;
371 const GList *channels;
372 GList *l;
373 guint result = 0;
375 balance = dup_color_balance (src);
376 if (balance == NULL)
377 goto out;
379 channels = gst_color_balance_list_channels (balance);
381 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
383 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
384 int i;
386 for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
388 if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
390 result |= (1 << i);
391 break;
396 g_object_unref (balance);
398 out:
399 return result;
402 void
403 empathy_video_src_change_device (EmpathyGstVideoSrc *self,
404 const gchar *device)
406 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
407 GstState state;
409 gst_element_get_state (priv->src, &state, NULL, 0);
411 g_return_if_fail (state == GST_STATE_NULL);
413 g_object_set (priv->src, "device", device, NULL);
416 gchar *
417 empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
419 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
420 gchar *device;
422 g_object_get (priv->src, "device", &device, NULL);
424 return device;
427 void
428 empathy_video_src_set_framerate (GstElement *src,
429 guint framerate)
431 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
433 if (priv->videorate)
435 g_object_set (G_OBJECT (priv->videorate), "max-rate", framerate, NULL);
439 void
440 empathy_video_src_set_resolution (GstElement *src,
441 guint width,
442 guint height)
444 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
445 GstCaps *caps;
446 GstPad *srcpad, *peer;
448 g_return_if_fail (priv->capsfilter != NULL);
450 gst_element_set_locked_state (priv->src, TRUE);
451 gst_element_set_state (priv->src, GST_STATE_NULL);
453 srcpad = gst_element_get_static_pad (priv->src, "src");
454 peer = gst_pad_get_peer (srcpad);
456 /* Keep a ref as removing it from the bin will loose our reference */
457 gst_object_ref (priv->src);
458 gst_bin_remove (GST_BIN (src), priv->src);
460 g_object_get (priv->capsfilter, "caps", &caps, NULL);
461 caps = gst_caps_make_writable (caps);
463 gst_caps_set_simple (caps,
464 "width", G_TYPE_INT, width,
465 "height", G_TYPE_INT, height,
466 NULL);
468 g_object_set (priv->capsfilter, "caps", caps, NULL);
469 gst_caps_unref (caps);
471 gst_bin_add (GST_BIN (src), priv->src);
472 /* We as the bin own the source again, so drop the temporary ref */
473 gst_object_unref (priv->src);
475 gst_pad_link (srcpad, peer);
477 gst_element_set_locked_state (priv->src, FALSE);
478 gst_element_sync_state_with_parent (priv->src);
480 gst_object_unref (srcpad);
481 gst_object_unref (peer);