]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-video-src.c
Merge branch 'subscription-msg-630707'
[empathy.git] / libempathy-gtk / empathy-video-src.c
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>
5  *
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.
10  *
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.
15  *
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
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <gst/interfaces/colorbalance.h>
26
27 #include "empathy-video-src.h"
28
29 G_DEFINE_TYPE(EmpathyGstVideoSrc, empathy_video_src, GST_TYPE_BIN)
30
31 /* Keep in sync with EmpathyGstVideoSrcChannel */
32 static const gchar *channel_names[NR_EMPATHY_GST_VIDEO_SRC_CHANNELS] = {
33   "contrast", "brightness", "gamma" };
34
35 /* signal enum */
36 #if 0
37 enum
38 {
39     LAST_SIGNAL
40 };
41
42 static guint signals[LAST_SIGNAL] = {0};
43 #endif
44
45 /* private structure */
46 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate;
47
48 struct _EmpathyGstVideoSrcPrivate
49 {
50   gboolean dispose_has_run;
51   GstElement *src;
52   /* Element implementing a ColorBalance interface */
53   GstElement *balance;
54 };
55
56 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
57   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
58     EmpathyGstVideoSrcPrivate))
59 /**
60  * empathy_gst_add_to_bin - create a new gst element, add to bin and link it.
61  * @bin - bin to add the new element to.
62  * @src - src element for the new element (may be NULL).
63  * @name - name of the factory for the new element
64  *
65  * Returns: The newly created element ot %NULL on failure
66  */
67 static GstElement *
68 empathy_gst_add_to_bin (GstBin *bin,
69   GstElement *src,
70   const gchar *factoryname)
71 {
72   GstElement *ret;
73
74   if ((ret = gst_element_factory_make (factoryname, NULL)) == NULL)
75   {
76     g_message ("Element factory \"%s\" not found.", factoryname);
77     goto error;
78   }
79
80   if (!gst_bin_add (bin, ret))
81   {
82     g_warning ("Couldn't add \"%s\" to bin.", factoryname);
83     goto error;
84   }
85
86   /* do not link if src == NULL, just exit here */
87   if (src == NULL)
88     return ret;
89
90   if (!gst_element_link (src, ret))
91   {
92     g_warning ("Failed to link \"%s\".", factoryname);
93     gst_bin_remove (bin, ret);
94     goto error;
95   }
96
97   return ret;
98
99 error:
100   if (ret != NULL)
101     gst_object_unref (ret);
102   return NULL;
103 }
104
105
106 static void
107 empathy_video_src_init (EmpathyGstVideoSrc *obj)
108 {
109   EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj);
110   GstElement *element, *element_back;
111   GstPad *ghost, *src;
112   GstCaps *caps;
113   gchar *str;
114
115   /* allocate caps here, so we can update it by optional elements */
116   caps = gst_caps_new_simple ("video/x-raw-yuv",
117     "width", G_TYPE_INT, 320,
118     "height", G_TYPE_INT, 240,
119     NULL);
120
121   /* allocate any data required by the object here */
122   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
123       NULL, "gconfvideosrc")) == NULL)
124     g_error ("Couldn't add \"gconfvideosrc\" (gst-plugins-good missing?)");
125
126   /* we need to save our source to priv->src */
127   priv->src = element;
128
129   /* videomaxrate is optional as it's part of gst-plugins-bad. So don't
130    * fail if it doesn't exist. */
131   element_back = element;
132   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
133       element, "videomaxrate")) == NULL)
134     {
135       g_message ("Couldn't add \"videomaxrate\" (gst-plugins-bad missing?)");
136       element = element_back;
137     }
138   else
139     {
140       gst_caps_set_simple (caps,
141         "framerate", GST_TYPE_FRACTION, 15, 1,
142         NULL);
143     }
144
145   str = gst_caps_to_string (caps);
146   g_debug ("Current video src caps are : %s", str);
147   g_free (str);
148
149   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
150       element, "ffmpegcolorspace")) == NULL)
151     g_error ("Failed to add \"ffmpegcolorspace\" (gst-plugins-base missing?)");
152
153   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
154       element, "videoscale")) == NULL)
155     g_error ("Failed to add \"videoscale\", (gst-plugins-base missing?)");
156
157   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
158       element, "capsfilter")) == NULL)
159     g_error (
160       "Failed to add \"capsfilter\" (gstreamer core elements missing?)");
161
162   g_object_set (G_OBJECT (element), "caps", caps, NULL);
163
164
165   /* optionally add postproc_tmpnoise to improve the performance of encoders */
166   element_back = element;
167   if ((element = empathy_gst_add_to_bin (GST_BIN (obj),
168       element, "postproc_tmpnoise")) == NULL)
169     {
170       g_message ("Failed to add \"postproc_tmpnoise\" (gst-ffmpeg missing?)");
171       element = element_back;
172     }
173
174   src = gst_element_get_static_pad (element, "src");
175   g_assert (src != NULL);
176
177   ghost = gst_ghost_pad_new ("src", src);
178   if (ghost == NULL)
179     g_error ("Unable to create ghost pad for the videosrc");
180
181   if (!gst_element_add_pad (GST_ELEMENT (obj), ghost))
182     g_error ("pad with the same name already existed or "
183             "the pad already had another parent.");
184
185   gst_object_unref (G_OBJECT (src));
186 }
187
188 static void empathy_video_src_dispose (GObject *object);
189 static void empathy_video_src_finalize (GObject *object);
190
191 static void
192 empathy_video_src_class_init (EmpathyGstVideoSrcClass *empathy_video_src_class)
193 {
194   GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_src_class);
195
196   g_type_class_add_private (empathy_video_src_class,
197     sizeof (EmpathyGstVideoSrcPrivate));
198
199   object_class->dispose = empathy_video_src_dispose;
200   object_class->finalize = empathy_video_src_finalize;
201 }
202
203 void
204 empathy_video_src_dispose (GObject *object)
205 {
206   EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
207   EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
208
209   if (priv->dispose_has_run)
210     return;
211
212   priv->dispose_has_run = TRUE;
213
214   /* release any references held by the object here */
215
216   if (G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose)
217     G_OBJECT_CLASS (empathy_video_src_parent_class)->dispose (object);
218 }
219
220 void
221 empathy_video_src_finalize (GObject *object)
222 {
223   //EmpathyGstVideoSrc *self = EMPATHY_GST_VIDEO_SRC (object);
224   //EmpathyGstVideoSrcPrivate *priv = EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self);
225
226   /* free any data held directly by the object here */
227
228   G_OBJECT_CLASS (empathy_video_src_parent_class)->finalize (object);
229 }
230
231 GstElement *
232 empathy_video_src_new (void)
233 {
234   static gboolean registered = FALSE;
235
236   if (!registered) {
237     if (!gst_element_register (NULL, "empathyvideosrc",
238             GST_RANK_NONE, EMPATHY_TYPE_GST_VIDEO_SRC))
239       return NULL;
240     registered = TRUE;
241   }
242   return gst_element_factory_make ("empathyvideosrc", NULL);
243 }
244
245 void
246 empathy_video_src_set_channel (GstElement *src,
247   EmpathyGstVideoSrcChannel channel, guint percent)
248 {
249   GstElement *color;
250   GstColorBalance *balance;
251   const GList *channels;
252   GList *l;
253
254   /* Find something supporting GstColorBalance */
255   color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
256
257   if (color == NULL)
258     return;
259
260   balance = GST_COLOR_BALANCE (color);
261
262   channels = gst_color_balance_list_channels (balance);
263
264   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
265     {
266       GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
267
268       if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
269         {
270           gst_color_balance_set_value (balance, c,
271             ((c->max_value - c->min_value) * percent)/100
272               + c->min_value);
273           break;
274         }
275     }
276
277   g_object_unref (color);
278 }
279
280 guint
281 empathy_video_src_get_channel (GstElement *src,
282   EmpathyGstVideoSrcChannel channel)
283 {
284   GstElement *color;
285   GstColorBalance *balance;
286   const GList *channels;
287   GList *l;
288   guint percent = 0;
289
290   /* Find something supporting GstColorBalance */
291   color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
292
293   if (color == NULL)
294     return percent;
295
296   balance = GST_COLOR_BALANCE (color);
297
298   channels = gst_color_balance_list_channels (balance);
299
300   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
301     {
302       GstColorBalanceChannel *c = GST_COLOR_BALANCE_CHANNEL (l->data);
303
304       if (g_ascii_strcasecmp (c->label, channel_names[channel]) == 0)
305         {
306           percent =
307             ((gst_color_balance_get_value (balance, c)
308                 - c->min_value) * 100) /
309               (c->max_value - c->min_value);
310
311           break;
312         }
313     }
314
315   g_object_unref (color);
316
317   return percent;
318 }
319
320
321 guint
322 empathy_video_src_get_supported_channels (GstElement *src)
323 {
324   GstElement *color;
325   GstColorBalance *balance;
326   const GList *channels;
327   GList *l;
328   guint result = 0;
329
330   /* Find something supporting GstColorBalance */
331   color = gst_bin_get_by_interface (GST_BIN (src), GST_TYPE_COLOR_BALANCE);
332
333   if (color == NULL)
334     goto out;
335
336   balance = GST_COLOR_BALANCE (color);
337
338   channels = gst_color_balance_list_channels (balance);
339
340   for (l = (GList *) channels; l != NULL; l = g_list_next (l))
341     {
342       GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (l->data);
343       int i;
344
345       for (i = 0; i < NR_EMPATHY_GST_VIDEO_SRC_CHANNELS; i++)
346         {
347           if (g_ascii_strcasecmp (channel->label, channel_names[i]) == 0)
348             {
349               result |= (1 << i);
350               break;
351             }
352         }
353     }
354
355   g_object_unref (color);
356
357 out:
358   return result;
359 }
360