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 "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" };
42 static guint signals
[LAST_SIGNAL
] = {0};
45 /* private structure */
46 typedef struct _EmpathyGstVideoSrcPrivate EmpathyGstVideoSrcPrivate
;
48 struct _EmpathyGstVideoSrcPrivate
50 gboolean dispose_has_run
;
52 /* Element implementing a ColorBalance interface */
54 /* Elements for resolution and framerate adjustment */
55 GstElement
*capsfilter
;
56 GstElement
*videorate
;
62 #define EMPATHY_GST_VIDEO_SRC_GET_PRIVATE(o) \
63 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_VIDEO_SRC, \
64 EmpathyGstVideoSrcPrivate))
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
74 empathy_gst_add_to_bin (GstBin
*bin
,
76 const gchar
*factoryname
)
80 if ((ret
= gst_element_factory_make (factoryname
, NULL
)) == NULL
)
82 g_message ("Element factory \"%s\" not found.", factoryname
);
86 if (!gst_bin_add (bin
, ret
))
88 g_warning ("Couldn't add \"%s\" to bin.", factoryname
);
92 /* do not link if src == NULL, just exit here */
96 if (!gst_element_link (src
, ret
))
98 g_warning ("Failed to link \"%s\".", factoryname
);
99 gst_bin_remove (bin
, ret
);
107 gst_object_unref (ret
);
111 static GstPadProbeReturn
112 empathy_video_src_drop_eos (GstPad
*pad
,
113 GstPadProbeInfo
*info
,
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
;
123 empathy_video_src_init (EmpathyGstVideoSrc
*obj
)
125 EmpathyGstVideoSrcPrivate
*priv
= EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (obj
);
126 GstElement
*element
, *element_back
;
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,
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 */
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
),
165 "average-period", GST_SECOND
/2,
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,
181 str
= gst_caps_to_string (caps
);
182 DEBUG ("Current video src caps are : %s", 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
)
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
);
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
);
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
;
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
)
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
);
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
);
269 empathy_video_src_new (void)
271 static gboolean registered
= FALSE
;
274 if (!gst_element_register (NULL
, "empathyvideosrc",
275 GST_RANK_NONE
, EMPATHY_TYPE_GST_VIDEO_SRC
))
279 return gst_element_factory_make ("empathyvideosrc", NULL
);
282 static GstColorBalance
*
283 dup_color_balance (GstElement
*src
)
287 /* Find something supporting GstColorBalance */
288 color
= gst_bin_get_by_interface (GST_BIN (src
), GST_TYPE_COLOR_BALANCE
);
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
);
302 return GST_COLOR_BALANCE (color
);
306 empathy_video_src_set_channel (GstElement
*src
,
307 EmpathyGstVideoSrcChannel channel
, guint percent
)
309 GstColorBalance
*balance
;
310 const GList
*channels
;
313 balance
= dup_color_balance (src
);
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
332 g_object_unref (balance
);
336 empathy_video_src_get_channel (GstElement
*src
,
337 EmpathyGstVideoSrcChannel channel
)
339 GstColorBalance
*balance
;
340 const GList
*channels
;
344 balance
= dup_color_balance (src
);
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)
357 ((gst_color_balance_get_value (balance
, c
)
358 - c
->min_value
) * 100) /
359 (c
->max_value
- c
->min_value
);
365 g_object_unref (balance
);
372 empathy_video_src_get_supported_channels (GstElement
*src
)
374 GstColorBalance
*balance
;
375 const GList
*channels
;
379 balance
= dup_color_balance (src
);
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
);
390 for (i
= 0; i
< NR_EMPATHY_GST_VIDEO_SRC_CHANNELS
; i
++)
392 if (g_ascii_strcasecmp (channel
->label
, channel_names
[i
]) == 0)
400 g_object_unref (balance
);
407 empathy_video_src_change_device (EmpathyGstVideoSrc
*self
,
410 EmpathyGstVideoSrcPrivate
*priv
= EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self
);
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
);
421 empathy_video_src_dup_device (EmpathyGstVideoSrc
*self
)
423 EmpathyGstVideoSrcPrivate
*priv
= EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (self
);
426 g_object_get (priv
->src
, "device", &device
, NULL
);
432 empathy_video_src_set_framerate (GstElement
*src
,
435 EmpathyGstVideoSrcPrivate
*priv
= EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src
);
439 g_object_set (G_OBJECT (priv
->videorate
), "max-rate", framerate
, NULL
);
444 empathy_video_src_set_resolution (GstElement
*src
,
448 EmpathyGstVideoSrcPrivate
*priv
= EMPATHY_GST_VIDEO_SRC_GET_PRIVATE (src
);
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
,
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
);