1 /*
2 * GStreamer
3 * Copyright (C) 2008-2009 Filippo Argiolas <filippo.argiolas@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #define GLIB_DISABLE_DEPRECATION_WARNINGS
25
26 #include <gst/gst.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdk.h>
29 #include <gdk-pixbuf/gdk-pixbuf.h>
30
31 #include "../gstgtk.h"
32
33 #include <gst/video/videooverlay.h>
34
35 #ifdef HAVE_X11
36 #include <X11/Xlib.h>
37 #endif
38
39 static gint delay = 0;
40 static gint saveddelay = 0;
41 static gint method = 1;
42
43 struct _SourceData
44 {
45 gpointer data;
46 gpointer nick;
47 gpointer value;
48 };
49 typedef struct _SourceData SourceData;
50
51 static GstBusSyncReply
create_window(GstBus * bus,GstMessage * message,GtkWidget * widget)52 create_window (GstBus * bus, GstMessage * message, GtkWidget * widget)
53 {
54 // ignore anything but 'prepare-window-handle' element messages
55 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
56 return GST_BUS_PASS;
57
58 if (!gst_is_video_overlay_prepare_window_handle_message (message))
59 return GST_BUS_PASS;
60
61 gst_video_overlay_set_gtk_window (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC
62 (message)), widget);
63
64 gst_message_unref (message);
65
66 return GST_BUS_DROP;
67 }
68
69 static void
message_cb(GstBus * bus,GstMessage * message,GstElement * pipeline)70 message_cb (GstBus * bus, GstMessage * message, GstElement * pipeline)
71 {
72 gst_element_set_state (pipeline, GST_STATE_NULL);
73 gst_object_unref (pipeline);
74
75 gtk_main_quit ();
76 }
77
78 static gboolean
expose_cb(GtkWidget * widget,cairo_t * cr,GstElement * videosink)79 expose_cb (GtkWidget * widget, cairo_t * cr, GstElement * videosink)
80 {
81 gst_video_overlay_expose (GST_VIDEO_OVERLAY (videosink));
82 return FALSE;
83 }
84
85 static void
destroy_cb(GtkWidget * widget,GdkEvent * event,GstElement * pipeline)86 destroy_cb (GtkWidget * widget, GdkEvent * event, GstElement * pipeline)
87 {
88 g_message ("destroy callback");
89
90 gst_element_set_state (pipeline, GST_STATE_NULL);
91 gst_object_unref (pipeline);
92
93 gtk_main_quit ();
94 }
95
96 static gboolean
play_cb(GtkWidget * widget,gpointer data)97 play_cb (GtkWidget * widget, gpointer data)
98 {
99 g_message ("playing");
100 gst_element_set_state (GST_ELEMENT (data), GST_STATE_PLAYING);
101 return FALSE;
102 }
103
104 static gboolean
null_cb(GtkWidget * widget,gpointer data)105 null_cb (GtkWidget * widget, gpointer data)
106 {
107 g_message ("nulling");
108 gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL);
109 return FALSE;
110 }
111
112 static gboolean
ready_cb(GtkWidget * widget,gpointer data)113 ready_cb (GtkWidget * widget, gpointer data)
114 {
115 g_message ("readying");
116 gst_element_set_state (GST_ELEMENT (data), GST_STATE_READY);
117 return FALSE;
118 }
119
120 static gboolean
pause_cb(GtkWidget * widget,gpointer data)121 pause_cb (GtkWidget * widget, gpointer data)
122 {
123 g_message ("pausing");
124 gst_element_set_state (GST_ELEMENT (data), GST_STATE_PAUSED);
125 return FALSE;
126 }
127
128 static gboolean
set_location_delayed(gpointer data)129 set_location_delayed (gpointer data)
130 {
131 SourceData *sdata = (SourceData *) data;
132 delay--;
133 g_print ("%d\n", delay);
134 if (delay > 0) {
135 return TRUE;
136 }
137 g_object_set (G_OBJECT (sdata->data), sdata->nick, sdata->value, NULL);
138 delay = saveddelay;
139 return FALSE;
140 }
141
142 static void
on_drag_data_received(GtkWidget * widget,GdkDragContext * context,int x,int y,GtkSelectionData * seldata,guint inf,guint time,gpointer data)143 on_drag_data_received (GtkWidget * widget,
144 GdkDragContext * context, int x, int y,
145 GtkSelectionData * seldata, guint inf, guint time, gpointer data)
146 {
147 SourceData *userdata = g_new0 (SourceData, 1);
148 GdkPixbufFormat *format;
149 gchar **uris = gtk_selection_data_get_uris (seldata);
150 gchar *filename = NULL;
151
152 g_return_if_fail (uris != NULL);
153 filename = g_filename_from_uri (uris[0], NULL, NULL);
154 g_return_if_fail (filename != NULL);
155 format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
156 g_return_if_fail (format);
157 g_print ("received %s image: %s\n", filename,
158 gdk_pixbuf_format_get_name (format));
159
160 userdata->nick = (gchar *) "location";
161 userdata->value = g_strdup (filename);
162 userdata->data = data;
163 saveddelay = delay;
164 if (delay > 0) {
165 g_print ("%d\n", delay);
166 g_timeout_add_seconds (1, set_location_delayed, userdata);
167 } else
168 g_object_set (G_OBJECT (userdata->data), userdata->nick, userdata->value,
169 NULL);
170 g_free (filename);
171 }
172
173
174 gint
main(gint argc,gchar * argv[])175 main (gint argc, gchar * argv[])
176 {
177 GstElement *pipeline;
178 GstElement *filter, *sink;
179 GstElement *sourcebin;
180 GstBus *bus;
181 GError *error = NULL;
182
183 GtkWidget *window;
184 GtkWidget *screen;
185 GtkWidget *vbox;
186 GtkWidget *hbox;
187 GtkWidget *play, *pause, *null, *ready;
188
189 gchar **source_desc_array = NULL;
190 gchar *source_desc = NULL;
191
192 GOptionContext *context;
193 GOptionEntry options[] = {
194 {"source-bin", 's', 0, G_OPTION_ARG_STRING_ARRAY, &source_desc_array,
195 "Use a custom source bin description (gst-launch style)", NULL}
196 ,
197 {"method", 'm', 0, G_OPTION_ARG_INT, &method,
198 "1 for gstdifferencematte, 2 for gloverlay", "M"}
199 ,
200 {"delay", 'd', 0, G_OPTION_ARG_INT, &delay,
201 "Wait N seconds before to send the image to gstreamer (useful with differencematte)",
202 "N"}
203 ,
204 {NULL}
205 };
206
207 #ifdef HAVE_X11
208 XInitThreads ();
209 #endif
210
211 context = g_option_context_new (NULL);
212 g_option_context_add_main_entries (context, options, NULL);
213 g_option_context_add_group (context, gst_init_get_option_group ());
214 g_option_context_add_group (context, gtk_get_option_group (TRUE));
215 if (!g_option_context_parse (context, &argc, &argv, &error)) {
216 g_print ("Inizialization error: %s\n", GST_STR_NULL (error->message));
217 g_option_context_free (context);
218 g_clear_error (&error);
219 return -1;
220 }
221 g_option_context_free (context);
222
223 if (source_desc_array != NULL) {
224 source_desc = g_strjoinv (" ", source_desc_array);
225 g_strfreev (source_desc_array);
226 }
227 if (source_desc == NULL) {
228 source_desc =
229 g_strdup
230 ("videotestsrc ! video/x-raw, width=352, height=288 ! identity ! glupload");
231 }
232
233 sourcebin =
234 gst_parse_bin_from_description (g_strdup (source_desc), TRUE, &error);
235 g_free (source_desc);
236 if (error) {
237 g_print ("Error while parsing source bin description: %s\n",
238 GST_STR_NULL (error->message));
239 return -1;
240 }
241
242 g_set_application_name ("gst-gl-effects test app");
243
244 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
245 gtk_container_set_border_width (GTK_CONTAINER (window), 3);
246
247 pipeline = gst_pipeline_new ("pipeline");
248
249 if (method == 2) {
250 filter = gst_element_factory_make ("gloverlay", "flt");
251 } else {
252 filter = gst_element_factory_make ("gldifferencematte", "flt");
253 }
254 sink = gst_element_factory_make ("glimagesink", "glsink");
255
256 gst_bin_add_many (GST_BIN (pipeline), sourcebin, filter, sink, NULL);
257
258 if (!gst_element_link_many (sourcebin, filter, sink, NULL)) {
259 g_print ("Failed to link one or more elements!\n");
260 return -1;
261 }
262
263 g_signal_connect (G_OBJECT (window), "delete-event",
264 G_CALLBACK (destroy_cb), pipeline);
265 g_signal_connect (G_OBJECT (window), "destroy-event",
266 G_CALLBACK (destroy_cb), pipeline);
267
268 screen = gtk_drawing_area_new ();
269
270 gtk_widget_set_size_request (screen, 640, 480); // 500 x 376
271
272 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
273
274 gtk_box_pack_start (GTK_BOX (vbox), screen, TRUE, TRUE, 0);
275
276 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
277
278 play = gtk_button_new_with_label ("PLAY");
279
280 g_signal_connect (G_OBJECT (play), "clicked", G_CALLBACK (play_cb), pipeline);
281
282 pause = gtk_button_new_with_label ("PAUSE");
283
284 g_signal_connect (G_OBJECT (pause), "clicked",
285 G_CALLBACK (pause_cb), pipeline);
286
287 null = gtk_button_new_with_label ("NULL");
288
289 g_signal_connect (G_OBJECT (null), "clicked", G_CALLBACK (null_cb), pipeline);
290
291 ready = gtk_button_new_with_label ("READY");
292
293 g_signal_connect (G_OBJECT (ready), "clicked",
294 G_CALLBACK (ready_cb), pipeline);
295
296 gtk_box_pack_start (GTK_BOX (hbox), null, TRUE, TRUE, 0);
297 gtk_box_pack_start (GTK_BOX (hbox), ready, TRUE, TRUE, 0);
298 gtk_box_pack_start (GTK_BOX (hbox), play, TRUE, TRUE, 0);
299 gtk_box_pack_start (GTK_BOX (hbox), pause, TRUE, TRUE, 0);
300
301 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
302
303 gtk_container_add (GTK_CONTAINER (window), vbox);
304
305 gtk_widget_realize (screen);
306
307 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
308 gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, screen,
309 NULL);
310 gst_bus_add_signal_watch (bus);
311 g_signal_connect (bus, "message::error", G_CALLBACK (message_cb), pipeline);
312 g_signal_connect (bus, "message::warning", G_CALLBACK (message_cb), pipeline);
313 g_signal_connect (bus, "message::eos", G_CALLBACK (message_cb), pipeline);
314 gst_object_unref (bus);
315 g_signal_connect (screen, "draw", G_CALLBACK (expose_cb), sink);
316
317 gtk_drag_dest_set (screen, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY);
318 gtk_drag_dest_add_uri_targets (screen);
319
320 g_signal_connect (screen, "drag-data-received",
321 G_CALLBACK (on_drag_data_received), filter);
322
323 gtk_widget_show_all (GTK_WIDGET (window));
324
325 gst_element_set_state (pipeline, GST_STATE_PLAYING);
326
327 gtk_main ();
328
329 return 0;
330 }
331