]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-video-widget.c
sink the videosink so we can hold a ref to it
[empathy.git] / libempathy-gtk / empathy-video-widget.c
1 /*
2  * empathy-gst-gtk-widget.c - Source for EmpathyVideoWidget
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 <gdk/gdkx.h>
26 #include <gst/interfaces/xoverlay.h>
27 #include <gst/farsight/fs-element-added-notifier.h>
28
29 #include "empathy-video-widget.h"
30
31 G_DEFINE_TYPE(EmpathyVideoWidget, empathy_video_widget,
32   GTK_TYPE_DRAWING_AREA)
33
34 static void empathy_video_widget_element_added_cb (
35   FsElementAddedNotifier *notifier, GstBin *bin, GstElement *element,
36   EmpathyVideoWidget *self);
37
38 static void empathy_video_widget_sync_message_cb (
39   GstBus *bus, GstMessage *message, EmpathyVideoWidget *self);
40
41 /* signal enum */
42 #if 0
43 enum
44 {
45     LAST_SIGNAL
46 };
47
48 static guint signals[LAST_SIGNAL] = {0};
49 #endif
50
51 enum {
52   PROP_GST_ELEMENT = 1,
53   PROP_GST_BUS,
54 };
55
56 /* private structure */
57 typedef struct _EmpathyVideoWidgetPriv EmpathyVideoWidgetPriv;
58
59 struct _EmpathyVideoWidgetPriv
60 {
61   gboolean dispose_has_run;
62   GstBus *bus;
63   GstElement *videosink;
64   GstPad *sink_pad;
65   GstElement *overlay;
66   FsElementAddedNotifier *notifier;
67 };
68
69 #define GET_PRIV(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
70   EMPATHY_TYPE_GST_GTK_WIDGET, EmpathyVideoWidgetPriv))
71
72 static void
73 empathy_video_widget_init (EmpathyVideoWidget *obj)
74 {
75   EmpathyVideoWidgetPriv *priv = GET_PRIV (obj);
76
77   priv->notifier = fs_element_added_notifier_new ();
78   g_signal_connect (priv->notifier, "element-added",
79     G_CALLBACK (empathy_video_widget_element_added_cb),
80     obj);
81
82   gtk_widget_set_size_request (GTK_WIDGET (obj), 320, 240);
83
84   GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (obj), GTK_DOUBLE_BUFFERED);
85 }
86
87 static void
88 empathy_video_widget_constructed (GObject *object)
89 {
90   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
91
92   priv->videosink = gst_element_factory_make ("gconfvideosink", NULL);
93   gst_object_ref (priv->videosink);
94   gst_object_sink (priv->videosink);
95
96   priv->sink_pad = gst_element_get_static_pad (priv->videosink, "sink");
97
98   fs_element_added_notifier_add (priv->notifier, GST_BIN (priv->videosink));
99   gst_bus_enable_sync_message_emission (priv->bus);
100
101   g_signal_connect (priv->bus, "sync-message",
102     G_CALLBACK (empathy_video_widget_sync_message_cb), object);
103
104 }
105
106 static void empathy_video_widget_dispose (GObject *object);
107 static void empathy_video_widget_finalize (GObject *object);
108 static gboolean empathy_video_widget_expose_event (GtkWidget *widget,
109   GdkEventExpose *event);
110
111 static void
112 empathy_video_widget_set_property (GObject *object,
113   guint property_id, const GValue *value, GParamSpec *pspec)
114 {
115   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
116
117   switch (property_id)
118     {
119       case PROP_GST_BUS:
120         priv->bus = g_value_dup_object (value);
121         break;
122       default:
123         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124     }
125 }
126
127 static void
128 empathy_video_widget_get_property (GObject *object,
129   guint property_id, GValue *value, GParamSpec *pspec)
130 {
131   EmpathyVideoWidgetPriv *priv = GET_PRIV (object);
132
133   switch (property_id)
134     {
135       case PROP_GST_ELEMENT:
136         g_value_set_object (value, priv->videosink);
137         break;
138       case PROP_GST_BUS:
139         g_value_set_object (value, priv->bus);
140         break;
141       default:
142         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
143     }
144 }
145
146
147 static void
148 empathy_video_widget_class_init (
149   EmpathyVideoWidgetClass *empathy_video_widget_class)
150 {
151   GObjectClass *object_class = G_OBJECT_CLASS (empathy_video_widget_class);
152   GtkWidgetClass *widget_class =
153     GTK_WIDGET_CLASS (empathy_video_widget_class);
154   GParamSpec *param_spec;
155
156   g_type_class_add_private (empathy_video_widget_class,
157     sizeof (EmpathyVideoWidgetPriv));
158
159   object_class->dispose = empathy_video_widget_dispose;
160   object_class->finalize = empathy_video_widget_finalize;
161   object_class->constructed = empathy_video_widget_constructed;
162
163   object_class->set_property = empathy_video_widget_set_property;
164   object_class->get_property = empathy_video_widget_get_property;
165
166   widget_class->expose_event = empathy_video_widget_expose_event;
167
168   param_spec = g_param_spec_object ("gst-element",
169     "gst-element", "The underlaying gstreamer element",
170     GST_TYPE_ELEMENT,
171     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
172   g_object_class_install_property (object_class, PROP_GST_ELEMENT, param_spec);
173
174   param_spec = g_param_spec_object ("gst-bus",
175     "gst-bus",
176     "The toplevel bus from the pipeline in which this bin will be added",
177     GST_TYPE_BUS,
178     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
179   g_object_class_install_property (object_class, PROP_GST_BUS, param_spec);
180 }
181
182 void
183 empathy_video_widget_dispose (GObject *object)
184 {
185   EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
186   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
187
188   if (priv->dispose_has_run)
189     return;
190
191   priv->dispose_has_run = TRUE;
192
193   if (priv->bus != NULL)
194     g_object_unref (priv->bus);
195
196   priv->bus = NULL;
197
198   if (priv->videosink != NULL)
199     g_object_unref (priv->videosink);
200
201   priv->videosink = NULL;
202
203
204   /* release any references held by the object here */
205
206   if (G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose)
207     G_OBJECT_CLASS (empathy_video_widget_parent_class)->dispose (object);
208 }
209
210 void
211 empathy_video_widget_finalize (GObject *object)
212 {
213   //EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (object);
214   //EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
215
216   /* free any data held directly by the object here */
217
218   G_OBJECT_CLASS (empathy_video_widget_parent_class)->finalize (object);
219 }
220
221 static void
222 empathy_video_widget_element_added_cb (FsElementAddedNotifier *notifier,
223   GstBin *bin, GstElement *element, EmpathyVideoWidget *self)
224 {
225   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
226
227   if (priv->overlay == NULL && GST_IS_X_OVERLAY (element))
228     {
229       priv->overlay = element;
230       gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
231     }
232
233   if (g_object_class_find_property (
234       G_OBJECT_GET_CLASS (element), "force-aspect-ratio"))
235     {
236       g_object_set (G_OBJECT (element), "force-aspect-ratio", TRUE, NULL);
237     }
238 }
239
240 static void
241 empathy_video_widget_sync_message_cb (GstBus *bus, GstMessage *message,
242   EmpathyVideoWidget *self)
243 {
244   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
245   const GstStructure *s;
246
247   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
248     return;
249
250   if (GST_MESSAGE_SRC (message) != (GstObject *) priv->overlay)
251     return;
252
253   s = gst_message_get_structure (message);
254
255   if (gst_structure_has_name (s, "prepare-xwindow-id"))
256     {
257       gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
258         GDK_WINDOW_XID (GTK_WIDGET (self)->window));
259     }
260 }
261
262 static gboolean
263 empathy_video_widget_expose_event (GtkWidget *widget, GdkEventExpose *event)
264 {
265   EmpathyVideoWidget *self = EMPATHY_VIDEO_WIDGET (widget);
266   EmpathyVideoWidgetPriv *priv = GET_PRIV (self);
267
268   if (event != NULL && event->count > 0)
269     return TRUE;
270
271   if (priv->overlay == NULL)
272     return TRUE;
273
274   gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (priv->overlay),
275     GDK_WINDOW_XID (widget->window));
276
277   gst_x_overlay_expose (GST_X_OVERLAY (priv->overlay));
278
279   return TRUE;
280 }
281
282
283 GtkWidget *
284 empathy_video_widget_new (GstBus *bus)
285 {
286   g_return_val_if_fail (bus != NULL, NULL);
287
288   return GTK_WIDGET (g_object_new (EMPATHY_TYPE_GST_GTK_WIDGET,
289     "gst-bus", bus,
290     NULL));
291 }
292
293 GstPad *
294 empathy_video_widget_get_sink (EmpathyVideoWidget *widget)
295 {
296   EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
297
298   return priv->sink_pad;
299 }
300
301 GstElement *
302 empathy_video_widget_get_element (EmpathyVideoWidget *widget)
303 {
304   EmpathyVideoWidgetPriv *priv = GET_PRIV (widget);
305
306   return priv->videosink;
307 }