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;
62 gboolean has_videomaxrate;
65 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
66 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
67 EmpathyGstVideoSrcPrivate))
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
77 empathy_gst_add_to_bin (GstBin *bin,
79 const gchar *factoryname)
83 if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
85 g_message ("Element factory \"%s\" not found.", factoryname);
89 if (!gst_bin_add (bin, ret))
91 g_warning ("Couldn't add \"%s\" to bin.", factoryname);
95 /* do not link if src == NULL, just exit here */
99 if (!gst_element_link (src, ret))
101 g_warning ("Failed to link \"%s\".", factoryname);
102 gst_bin_remove (bin, ret);
110 gst_object_unref (ret);
116 empathy_video_src_init (EmpathyGstVideoSrc *obj)
118 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
119 GstElement *element, *element_back;
124 /* allocate caps here, so we can update it by optional elements */
125 caps = gst_caps_new_simple ("video/x-raw-yuv",
126 "width", G_TYPE_INT, 320,
127 "height", G_TYPE_INT, 240,
130 /* allocate any data required by the object here */
131 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
132 NULL, "v4l2src")) == NULL)
133 g_error ("Couldn't add \"v4l2src\" (gst-plugins-good missing?)");
135 /* we need to save our source to priv->src */
138 /* videomaxrate is optional as it's part of gst-plugins-bad. So don't
139 * fail if it doesn't exist. */
140 element_back = element;
141 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
142 element, "videomaxrate")) == NULL)
144 g_message ("Couldn't add \"videomaxrate\" (gst-plugins-bad missing?)");
145 element = element_back;
146 priv->has_videomaxrate = TRUE;
150 priv->has_videomaxrate = TRUE;
153 gst_caps_set_simple (caps,
154 "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, 30, 1,
157 str = gst_caps_to_string (caps);
158 DEBUG ("Current video src caps are : %s", str);
161 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
162 element, "ffmpegcolorspace")) == NULL)
163 g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
165 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
166 element, "videoscale")) == NULL)
167 g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
169 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
170 element, "capsfilter")) == NULL)
172 "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
174 priv->capsfilter = element;
175 g_object_set (G_OBJECT (element), "caps", caps, NULL);
178 /* optionally add postproc_tmpnoise to improve the performance of encoders */
179 element_back = element;
180 if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
181 element, "postproc_tmpnoise")) == NULL)
183 g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
184 element = element_back;
187 src = gst_element_get_static_pad (element, "src");
188 g_assert (src != NULL);
190 ghost = gst_ghost_pad_new ("src", src);
192 g_error ("Unable to create ghost pad for the videosrc");
194 if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
195 g_error ("pad with the same name already existed or "
196 "the pad already had another parent.");
198 gst_object_unref (G_OBJECT (src));
201 static void empathy_video_src_dispose (GObject *object);
202 static void empathy_video_src_finalize (GObject *object);
205 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
207 GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
209 g_type_class_add_private (empathy_video_src_class,
210 sizeof (EmpathyGstVideoSrcPrivate));
212 object_class->dispose = empathy_video_src_dispose;
213 object_class->finalize = empathy_video_src_finalize;
217 empathy_video_src_dispose (GObject *object)
219 EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
220 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
222 if (priv->dispose_has_run)
225 priv->dispose_has_run = TRUE;
227 /* release any references held by the object here */
229 if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
230 G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
234 empathy_video_src_finalize (GObject *object)
236 //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
237 //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
239 /* free any data held directly by the object here */
241 G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
245 empathy_video_src_new (void)
247 static gboolean registered = FALSE;
250 if (!gst_element_register (NULL, "empathyvideosrc",
251 GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
255 return gst_element_factory_make ("empathyvideosrc", NULL);
258 static GstColorBalance *
259 dup_color_balance (GstElement *src)
263 /* Find something supporting GstColorBalance */
264 color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
269 /* colorbalance is wrapped by GstImplementsInterface, we
270 * need to check if it is actually supported for this instance
271 * in its current state before trying to use it */
272 if (!GST_IS_COLOR_BALANCE (color))
274 g_object_unref (color);
278 return GST_COLOR_BALANCE (color);
282 empathy_video_src_set_channel (GstElement *src,
283 EmpathyGstVideoSrcChannel channel, guint percent)
285 GstColorBalance *balance;
286 const GList *channels;
289 balance = dup_color_balance (src);
293 channels = gst_color_balance_list_channels (balance);
295 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
297 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
299 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
301 gst_color_balance_set_value (balance, c,
302 ((c->max_value - c->min_value) * percent)/100
308 g_object_unref (balance);
312 empathy_video_src_get_channel (GstElement *src,
313 EmpathyGstVideoSrcChannel channel)
315 GstColorBalance *balance;
316 const GList *channels;
320 balance = dup_color_balance (src);
324 channels = gst_color_balance_list_channels (balance);
326 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
328 GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
330 if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
333 ((gst_color_balance_get_value (balance, c)
334 - c->min_value) * 100) /
335 (c->max_value - c->min_value);
341 g_object_unref (balance);
348 empathy_video_src_get_supported_channels (GstElement *src)
350 GstColorBalance *balance;
351 const GList *channels;
355 balance = dup_color_balance (src);
359 channels = gst_color_balance_list_channels (balance);
361 for (l = (GList *) channels; l != NULL; l = g_list_next (l))
363 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
366 for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
368 if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
376 g_object_unref (balance);
383 empathy_video_src_change_device (EmpathyGstVideoSrc *self,
386 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
389 gst_element_get_state (priv->src, &state, NULL, 0);
391 g_return_if_fail (state == GST_STATE_NULL);
393 g_object_set (priv->src, "device", device, NULL);
397 empathy_video_src_dup_device (EmpathyGstVideoSrc *self)
399 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
402 g_object_get (priv->src, "device", &device, NULL);
408 empathy_video_src_set_framerate (GstElement *src,
411 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
414 if (priv->has_videomaxrate)
416 g_return_if_fail (priv->capsfilter != NULL);
418 g_object_get (priv->capsfilter, "caps", &caps, NULL);
419 caps = gst_caps_make_writable (caps);
421 gst_caps_set_simple (caps,
422 "framerate", GST_TYPE_FRACTION, framerate, 1,
425 g_object_set (priv->capsfilter, "caps", caps, NULL);
430 empathy_video_src_set_resolution (GstElement *src,
434 EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src);
438 g_return_if_fail (priv->capsfilter != NULL);
440 gst_element_set_locked_state (priv->src, TRUE);
441 gst_element_set_state (priv->src, GST_STATE_NULL);
443 g_object_get (priv->capsfilter, "caps", &caps, NULL);
444 caps = gst_caps_make_writable (caps);
446 gst_caps_set_simple (caps,
447 "width", G_TYPE_INT, width,
448 "height", G_TYPE_INT, height,
451 g_object_set (priv->capsfilter, "caps", caps, NULL);
453 /* Reset clock an base time, this is require for videotestsrc and hopefully
454 * has no side effect */
455 gst_clock = gst_element_get_clock (src);
456 gst_element_set_clock (priv->src, gst_clock);
457 gst_element_set_base_time (priv->src, gst_element_get_base_time (src));
458 gst_object_unref (gst_clock);
460 gst_element_set_locked_state (priv->src, FALSE);
461 gst_element_sync_state_with_parent (priv->src);