Updated Spanish translation
[empathy-mirror.git] / src / empathy-video-src.c
blob3b9e6f8fc9bce3235d446a7268106e2ee13d3dd1
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
22 #include <stdio.h>
23 #include <stdlib.h>
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" };
38 /* signal enum */
39 #if 0
40 enum
42 LAST_SIGNAL
45 static guint signals[LAST_SIGNAL] = {0};
46 #endif
48 /* private structure */
49 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate;
51 struct _EmpathyGstVideoSrcPrivate
53 gboolean dispose_has_run;
54 GstElement *src;
55 /* Element implementing a ColorBalance interface */
56 GstElement *balance;
57 /* Elements for resolution and framerate adjustment */
58 GstElement *capsfilter;
59 GstElement *videorate;
60 guint width;
61 guint height;
62 guint framerate;
65 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
66 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
67 EmpathyGstVideoSrcPrivate))
68 /**
69 * empathy_gst_add_to_bin - create a new gst element, add to bin and link it.
70 * @bin - bin to add the new element to.
71 * @src - src element for the new element (may be NULL).
72 * @name - name of the factory for the new element
74 * Returns: The newly created element ot %NULL on failure
76 static GstElement *
77 empathy_gst_add_to_bin (GstBin *bin,
78 GstElement *src,
79 const gchar *factoryname)
81 GstElement *ret;
83 if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
85 g_message ("Element factory \"%s\" not found.", factoryname);
86 goto error;
89 if (!gst_bin_add (bin, ret))
91 g_warning ("Couldn't add \"%s\" to bin.", factoryname);
92 goto error;
95 /* do not link if src == NULL, just exit here */
96 if (src == NULL)
97 return ret;
99 if (!gst_element_link (src, ret))
101 g_warning ("Failed to link \"%s\".", factoryname);
102 gst_bin_remove (bin, ret);
103 goto error;
106 return ret;
108 error:
109 if (ret != NULL)
110 gst_object_unref (ret);
111 return NULL;
114 static gboolean
115 empathy_video_src_drop_eos (GstPad *pad, GstEvent *event, gpointer user_data)
117 return GST_EVENT_TYPE (event) != GST_EVENT_EOS;
120 static void
121 empathy_video_src_init (EmpathyGstVideoSrc *obj)
123 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
124 GstElement *element, *element_back;
125 GstPad *ghost, *src;
126 GstCaps *caps;
127 gchar *str;
129 /* allocate caps here, so we can update it by optional elements */
130 caps = gst_caps_new_simple ("video/x-raw-yuv",
131 "width", G_TYPE_INT, 320,
132 "height", G_TYPE_INT, 240,
133 NULL);
135 /* allocate any data required by the object here */
136 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
137 NULL, "v4l2src")) == NULL)
138 g_error ("Couldn't add \"v4l2src\" (gst-plugins-good missing?)");
140 /* we need to save our source to priv->src */
141 priv->src = element;
143 /* Drop EOS events, so that our sinks don't get confused when we restart the
144 * source (triggering an EOS) */
145 src = gst_element_get_static_pad (element, "src");
146 gst_pad_add_event_probe (src, G_CALLBACK (empathy_video_src_drop_eos), NULL);
147 gst_object_unref (src);
149 /* videorate with the required properties optional as it needs a currently
150 * unreleased gst-plugins-base 0.10.36 */
151 element_back = element;
152 element = empathy_gst_add_to_bin (GST_BIN (obj), element, "videorate");
154 if (element != NULL && g_object_class_find_property (
155 G_OBJECT_GET_CLASS (element), "max-rate") != NULL)
157 priv->videorate = element;
158 g_object_set (G_OBJECT (element),
159 "drop-only", TRUE,
160 "average-period", GST_SECOND/2,
161 NULL);
163 else
165 g_message ("videorate missing or doesn't have max-rate property, not"
166 "doing dynamic framerate changes (Needs gst-plugins-base >= 0.10.36)");
167 /* Refcount owned by the bin */
168 gst_bin_remove (GST_BIN (obj), element);
169 element = element_back;
172 gst_caps_set_simple (caps,
173 "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, 30, 1,
174 NULL);
176 str = gst_caps_to_string (caps);
177 DEBUG ("Current video src caps are : %s", str);
178 g_free (str);
180 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
181 element, "ffmpegcolorspace")) == NULL)
182 g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
184 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
185 element, "videoscale")) == NULL)
186 g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
188 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
189 element, "capsfilter")) == NULL)
190 g_error (
191 "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
193 priv->capsfilter = element;
194 g_object_set (G_OBJECT (element), "caps", caps, NULL);
197 /* optionally add postproc_tmpnoise to improve the performance of encoders */
198 element_back = element;
199 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
200 element, "postproc_tmpnoise")) == NULL)
202 g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
203 element = element_back;
206 src = gst_element_get_static_pad (element, "src");
207 g_assert (src != NULL);
209 ghost = gst_ghost_pad_new ("src", src);
210 if (ghost == NULL)
211 g_error ("Unable to create ghost pad for the videosrc");
213 if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
214 g_error ("pad with the same name already existed or "
215 "the pad already had another parent.");
217 gst_object_unref (G_OBJECT (src));
220 static void empathy_video_src_dispose (GObject *object);
221 static void empathy_video_src_finalize (GObject *object);
223 static void
224 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
226 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
228 g_type_class_add_private (empathy_video_src_class,
229 sizeof (EmpathyGstVideoSrcPrivate));
231 object_class->dispose = empathy_video_src_dispose;
232 object_class->finalize = empathy_video_src_finalize;
235 void
236 empathy_video_src_dispose (GObject *object)
238 EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
239 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
241 if (priv->dispose_has_run)
242 return;
244 priv->dispose_has_run = TRUE;
246 /* release any references held by the object here */
248 if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
249 G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
252 void
253 empathy_video_src_finalize (GObject *object)
255 //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
256 //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
258 /* free any data held directly by the object here */
260 G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
263 GstElement *
264 empathy_video_src_new (void)
266 static gboolean registered = FALSE;
268 if (!registered) {
269 if (!gst_element_register (NULL, "empathyvideosrc",
270 GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
271 return NULL;
272 registered = TRUE;
274 return gst_element_factory_make ("empathyvideosrc", NULL);
277 static GstColorBalance *
278 dup_color_balance (GstElement *src)
280 GstElement *color;
282 /* Find something supporting GstColorBalance */
283 color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
285 if (color == NULL)
286 return NULL;
288 /* colorbalance is wrapped by GstImplementsInterface, we
289 * need to check if it is actually supported for this instance
290 * in its current state before trying to use it */
291 if (!GST_IS_COLOR_BALANCE (color))
293 g_object_unref (color);
294 return NULL;
297 return GST_COLOR_BALANCE (color);
300 void
301 empathy_video_src_set_channel (GstElement *src,
302 EmpathyGstVideoSrcChannel channel, guint percent)
304 GstColorBalance *balance;
305 const GList *channels;
306 GList *l;
308 balance = dup_color_balance (src);
309 if (balance == NULL)
310 return;
312 channels = gst_color_balance_list_channels (balance);
314 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
316 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
318 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
320 gst_color_balance_set_value (balance, c,
321 ((c->max_value - c->min_value) * percent)/100
322 + c->min_value);
323 break;
327 g_object_unref (balance);
330 guint
331 empathy_video_src_get_channel (GstElement *src,
332 EmpathyGstVideoSrcChannel channel)
334 GstColorBalance *balance;
335 const GList *channels;
336 GList *l;
337 guint percent = 0;
339 balance = dup_color_balance (src);
340 if (balance == NULL)
341 return percent;
343 channels = gst_color_balance_list_channels (balance);
345 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
347 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
349 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
351 percent =
352 ((gst_color_balance_get_value (balance, c)
353 - c->min_value) * 100) /
354 (c->max_value - c->min_value);
356 break;
360 g_object_unref (balance);
362 return percent;
366 guint
367 empathy_video_src_get_supported_channels (GstElement *src)
369 GstColorBalance *balance;
370 const GList *channels;
371 GList *l;
372 guint result = 0;
374 balance = dup_color_balance (src);
375 if (balance == NULL)
376 goto out;
378 channels = gst_color_balance_list_channels (balance);
380 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
382 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
383 int i;
385 for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
387 if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
389 result |= (1 << i);
390 break;
395 g_object_unref (balance);
397 out:
398 return result;
401 void
402 empathy_video_src_change_device (EmpathyGstVideoSrc *self,
403 const gchar *device)
405 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
406 GstState state;
408 gst_element_get_state (priv->src, &state, NULL, 0);
410 g_return_if_fail (state == GST_STATE_NULL);
412 g_object_set (priv->src, "device", device, NULL);
415 gchar *
416 empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
418 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
419 gchar *device;
421 g_object_get (priv->src, "device", &device, NULL);
423 return device;
426 void
427 empathy_video_src_set_framerate (GstElement *src,
428 guint framerate)
430 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
432 if (priv->videorate)
434 g_object_set (G_OBJECT (priv->videorate), "max-rate", framerate, NULL);
438 void
439 empathy_video_src_set_resolution (GstElement *src,
440 guint width,
441 guint height)
443 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
444 GstCaps *caps;
445 GstPad *srcpad, *peer;
447 g_return_if_fail (priv->capsfilter != NULL);
449 gst_element_set_locked_state (priv->src, TRUE);
450 gst_element_set_state (priv->src, GST_STATE_NULL);
452 srcpad = gst_element_get_static_pad (priv->src, "src");
453 peer = gst_pad_get_peer (srcpad);
455 /* Keep a ref as removing it from the bin will loose our reference */
456 gst_object_ref (priv->src);
457 gst_bin_remove (GST_BIN (src), priv->src);
459 g_object_get (priv->capsfilter, "caps", &caps, NULL);
460 caps = gst_caps_make_writable (caps);
462 gst_caps_set_simple (caps,
463 "width", G_TYPE_INT, width,
464 "height", G_TYPE_INT, height,
465 NULL);
467 g_object_set (priv->capsfilter, "caps", caps, NULL);
468 gst_caps_unref (caps);
470 gst_bin_add (GST_BIN (src), priv->src);
471 /* We as the bin own the source again, so drop the temporary ref */
472 gst_object_unref (priv->src);
474 gst_pad_link (srcpad, peer);
476 gst_element_set_locked_state (priv->src, FALSE);
477 gst_element_sync_state_with_parent (priv->src);
479 gst_object_unref (srcpad);
480 gst_object_unref (peer);