Set prgname instead of program_class
[nijm-empathy.git] / src / empathy-video-src.c
blob41dea2377c3636a6f3f3952c5f621d0b726f2eef
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"
22 #include "empathy-video-src.h"
24 #include <gst/video/colorbalance.h>
26 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
27 #include "empathy-debug.h"
29 G_DEFINE_TYPE(EmpathyGstVideoSrc, empathy_video_src, GST_TYPE_BIN)
31 /* Keep in sync with EmpathyGstVideoSrcChannel */
32 static const gchar *channel_names[NR_EMPATHY_GST_VIDEO_SRC_CHANNELS] = {
33 "contrast", "brightness", "gamma" };
35 /* signal enum */
36 #if 0
37 enum
39 LAST_SIGNAL
42 static guint signals[LAST_SIGNAL] = {0};
43 #endif
45 /* private structure */
46 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate;
48 struct _EmpathyGstVideoSrcPrivate
50 gboolean dispose_has_run;
51 GstElement *src;
52 /* Element implementing a ColorBalance interface */
53 GstElement *balance;
54 /* Elements for resolution and framerate adjustment */
55 GstElement *capsfilter;
56 GstElement *videorate;
57 guint width;
58 guint height;
59 guint framerate;
62 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
63 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
64 EmpathyGstVideoSrcPrivate))
65 /**
66 * empathy_gst_add_to_bin - create a new gst element, add to bin and link it.
67 * @bin - bin to add the new element to.
68 * @src - src element for the new element (may be NULL).
69 * @name - name of the factory for the new element
71 * Returns: The newly created element ot %NULL on failure
73 static GstElement *
74 empathy_gst_add_to_bin (GstBin *bin,
75 GstElement *src,
76 const gchar *factoryname)
78 GstElement *ret;
80 if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
82 g_message ("Element factory \"%s\" not found.", factoryname);
83 goto error;
86 if (!gst_bin_add (bin, ret))
88 g_warning ("Couldn't add \"%s\" to bin.", factoryname);
89 goto error;
92 /* do not link if src == NULL, just exit here */
93 if (src == NULL)
94 return ret;
96 if (!gst_element_link (src, ret))
98 g_warning ("Failed to link \"%s\".", factoryname);
99 gst_bin_remove (bin, ret);
100 goto error;
103 return ret;
105 error:
106 if (ret != NULL)
107 gst_object_unref (ret);
108 return NULL;
111 static GstPadProbeReturn
112 empathy_video_src_drop_eos (GstPad *pad,
113 GstPadProbeInfo *info,
114 gpointer user_data)
116 if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_EVENT (info)) == GST_EVENT_EOS)
117 return GST_PAD_PROBE_DROP;
119 return GST_PAD_PROBE_OK;
122 static void
123 empathy_video_src_init (EmpathyGstVideoSrc *obj)
125 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
126 GstElement *element, *element_back;
127 GstPad *ghost, *src;
128 GstCaps *caps;
129 gchar *str;
131 /* allocate caps here, so we can update it by optional elements */
132 caps = gst_caps_new_simple ("video/x-raw",
133 "width", G_TYPE_INT, 320,
134 "height", G_TYPE_INT, 240,
135 NULL);
137 /* allocate any data required by the object here */
138 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
139 NULL, "v4l2src")) == NULL)
140 g_error ("Couldn't add \"v4l2src\" (gst-plugins-good missing?)");
142 /* we need to save our source to priv->src */
143 priv->src = element;
145 /* Drop EOS events, so that our sinks don't get confused when we restart the
146 * source (triggering an EOS) */
147 src = gst_element_get_static_pad (element, "src");
149 gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
150 empathy_video_src_drop_eos, NULL, NULL);
152 gst_object_unref (src);
154 /* videorate with the required properties optional as it needs a currently
155 * unreleased gst-plugins-base 0.10.36 */
156 element_back = element;
157 element = empathy_gst_add_to_bin (GST_BIN (obj), element, "videorate");
159 if (element != NULL && g_object_class_find_property (
160 G_OBJECT_GET_CLASS (element), "max-rate") != NULL)
162 priv->videorate = element;
163 g_object_set (G_OBJECT (element),
164 "drop-only", TRUE,
165 "average-period", GST_SECOND/2,
166 NULL);
168 else
170 g_message ("videorate missing or doesn't have max-rate property, not"
171 "doing dynamic framerate changes (Needs gst-plugins-base >= 0.10.36)");
172 /* Refcount owned by the bin */
173 gst_bin_remove (GST_BIN (obj), element);
174 element = element_back;
177 gst_caps_set_simple (caps,
178 "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, 30, 1,
179 NULL);
181 str = gst_caps_to_string (caps);
182 DEBUG ("Current video src caps are : %s", str);
183 g_free (str);
185 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
186 element, "videoconvert")) == NULL)
187 g_error ("Failed to add \"videoconvert\" (gst-plugins-base missing?)");
189 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
190 element, "videoscale")) == NULL)
191 g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
193 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
194 element, "capsfilter")) == NULL)
195 g_error (
196 "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
198 priv->capsfilter = element;
199 g_object_set (G_OBJECT (element), "caps", caps, NULL);
202 /* optionally add postproc_tmpnoise to improve the performance of encoders */
203 element_back = element;
204 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
205 element, "postproc_tmpnoise")) == NULL)
207 g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
208 element = element_back;
211 src = gst_element_get_static_pad (element, "src");
212 g_assert (src != NULL);
214 ghost = gst_ghost_pad_new ("src", src);
215 if (ghost == NULL)
216 g_error ("Unable to create ghost pad for the videosrc");
218 if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
219 g_error ("pad with the same name already existed or "
220 "the pad already had another parent.");
222 gst_object_unref (G_OBJECT (src));
225 static void empathy_video_src_dispose (GObject *object);
226 static void empathy_video_src_finalize (GObject *object);
228 static void
229 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
231 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
233 g_type_class_add_private (empathy_video_src_class,
234 sizeof (EmpathyGstVideoSrcPrivate));
236 object_class->dispose = empathy_video_src_dispose;
237 object_class->finalize = empathy_video_src_finalize;
240 void
241 empathy_video_src_dispose (GObject *object)
243 EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
244 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
246 if (priv->dispose_has_run)
247 return;
249 priv->dispose_has_run = TRUE;
251 /* release any references held by the object here */
253 if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
254 G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
257 void
258 empathy_video_src_finalize (GObject *object)
260 //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
261 //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
263 /* free any data held directly by the object here */
265 G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
268 GstElement *
269 empathy_video_src_new (void)
271 static gboolean registered = FALSE;
273 if (!registered) {
274 if (!gst_element_register (NULL, "empathyvideosrc",
275 GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
276 return NULL;
277 registered = TRUE;
279 return gst_element_factory_make ("empathyvideosrc", NULL);
282 static GstColorBalance *
283 dup_color_balance (GstElement *src)
285 GstElement *color;
287 /* Find something supporting GstColorBalance */
288 color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
290 if (color == NULL)
291 return NULL;
293 /* colorbalance is wrapped by GstImplementsInterface, we
294 * need to check if it is actually supported for this instance
295 * in its current state before trying to use it */
296 if (!GST_IS_COLOR_BALANCE (color))
298 g_object_unref (color);
299 return NULL;
302 return GST_COLOR_BALANCE (color);
305 void
306 empathy_video_src_set_channel (GstElement *src,
307 EmpathyGstVideoSrcChannel channel, guint percent)
309 GstColorBalance *balance;
310 const GList *channels;
311 GList *l;
313 balance = dup_color_balance (src);
314 if (balance == NULL)
315 return;
317 channels = gst_color_balance_list_channels (balance);
319 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
321 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
323 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
325 gst_color_balance_set_value (balance, c,
326 ((c->max_value - c->min_value) * percent)/100
327 + c->min_value);
328 break;
332 g_object_unref (balance);
335 guint
336 empathy_video_src_get_channel (GstElement *src,
337 EmpathyGstVideoSrcChannel channel)
339 GstColorBalance *balance;
340 const GList *channels;
341 GList *l;
342 guint percent = 0;
344 balance = dup_color_balance (src);
345 if (balance == NULL)
346 return percent;
348 channels = gst_color_balance_list_channels (balance);
350 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
352 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
354 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
356 percent =
357 ((gst_color_balance_get_value (balance, c)
358 - c->min_value) * 100) /
359 (c->max_value - c->min_value);
361 break;
365 g_object_unref (balance);
367 return percent;
371 guint
372 empathy_video_src_get_supported_channels (GstElement *src)
374 GstColorBalance *balance;
375 const GList *channels;
376 GList *l;
377 guint result = 0;
379 balance = dup_color_balance (src);
380 if (balance == NULL)
381 goto out;
383 channels = gst_color_balance_list_channels (balance);
385 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
387 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
388 int i;
390 for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
392 if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
394 result |= (1 << i);
395 break;
400 g_object_unref (balance);
402 out:
403 return result;
406 void
407 empathy_video_src_change_device (EmpathyGstVideoSrc *self,
408 const gchar *device)
410 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
411 GstState state;
413 gst_element_get_state (priv->src, &state, NULL, 0);
415 g_return_if_fail (state == GST_STATE_NULL);
417 g_object_set (priv->src, "device", device, NULL);
420 gchar *
421 empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
423 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
424 gchar *device;
426 g_object_get (priv->src, "device", &device, NULL);
428 return device;
431 void
432 empathy_video_src_set_framerate (GstElement *src,
433 guint framerate)
435 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
437 if (priv->videorate)
439 g_object_set (G_OBJECT (priv->videorate), "max-rate", framerate, NULL);
443 void
444 empathy_video_src_set_resolution (GstElement *src,
445 guint width,
446 guint height)
448 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
449 GstCaps *caps;
450 GstPad *srcpad, *peer;
452 g_return_if_fail (priv->capsfilter != NULL);
454 gst_element_set_locked_state (priv->src, TRUE);
455 gst_element_set_state (priv->src, GST_STATE_NULL);
457 srcpad = gst_element_get_static_pad (priv->src, "src");
458 peer = gst_pad_get_peer (srcpad);
460 /* Keep a ref as removing it from the bin will loose our reference */
461 gst_object_ref (priv->src);
462 gst_bin_remove (GST_BIN (src), priv->src);
464 g_object_get (priv->capsfilter, "caps", &caps, NULL);
465 caps = gst_caps_make_writable (caps);
467 gst_caps_set_simple (caps,
468 "width", G_TYPE_INT, width,
469 "height", G_TYPE_INT, height,
470 NULL);
472 g_object_set (priv->capsfilter, "caps", caps, NULL);
473 gst_caps_unref (caps);
475 gst_bin_add (GST_BIN (src), priv->src);
476 /* We as the bin own the source again, so drop the temporary ref */
477 gst_object_unref (priv->src);
479 gst_pad_link (srcpad, peer);
481 gst_element_set_locked_state (priv->src, FALSE);
482 gst_element_sync_state_with_parent (priv->src);
484 gst_object_unref (srcpad);
485 gst_object_unref (peer);