1 /*
2 * GStreamer
3 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
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 /*
21 * This is a demo application to test the camerabin element.
22 * If you have question don't hesitate in contact me edgard.lima@gmail.com
23 */
24
25 /*
26 * Includes
27 */
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "gst-camera2.h"
33
34 #include <string.h>
35
36 #include <gst/pbutils/encoding-profile.h>
37 #include <gst/gst.h>
38 #include <gst/video/videooverlay.h>
39 #include <gtk/gtk.h>
40 #include <gdk/gdkx.h>
41 #include <gdk/gdkkeysyms.h>
42
43 #define UI_FILE CAMERA_APPS_UIDIR G_DIR_SEPARATOR_S "gst-camera2.ui"
44
45 static GstElement *camera;
46 static GtkBuilder *builder;
47 static GtkWidget *ui_main_window;
48
49 typedef struct
50 {
51 const gchar *name;
52 GstEncodingProfile *(*create_profile) ();
53 } GstCameraVideoFormat;
54
55 static GstEncodingProfile *
create_ogg_profile(void)56 create_ogg_profile (void)
57 {
58 GstEncodingContainerProfile *container;
59 GstCaps *caps = NULL;
60
61 caps = gst_caps_new_empty_simple ("application/ogg");
62 container = gst_encoding_container_profile_new ("ogg", NULL, caps, NULL);
63 gst_caps_unref (caps);
64
65 caps = gst_caps_new_empty_simple ("video/x-theora");
66 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
67 gst_encoding_video_profile_new (caps, NULL, NULL, 1));
68 gst_caps_unref (caps);
69
70 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
71 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
72 gst_encoding_audio_profile_new (caps, NULL, NULL, 1));
73 gst_caps_unref (caps);
74
75 return (GstEncodingProfile *) container;
76 }
77
78 static GstEncodingProfile *
create_webm_profile(void)79 create_webm_profile (void)
80 {
81 GstEncodingContainerProfile *container;
82 GstCaps *caps = NULL;
83
84 caps = gst_caps_new_empty_simple ("video/webm");
85 container = gst_encoding_container_profile_new ("webm", NULL, caps, NULL);
86 gst_caps_unref (caps);
87
88 caps = gst_caps_new_empty_simple ("video/x-vp8");
89 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
90 gst_encoding_video_profile_new (caps, NULL, NULL, 1));
91 gst_caps_unref (caps);
92
93 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
94 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
95 gst_encoding_audio_profile_new (caps, NULL, NULL, 1));
96 gst_caps_unref (caps);
97
98 return (GstEncodingProfile *) container;
99 }
100
101 static GstEncodingProfile *
create_mp4_profile(void)102 create_mp4_profile (void)
103 {
104 GstEncodingContainerProfile *container;
105 GstCaps *caps = NULL;
106
107 caps =
108 gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, "iso",
109 NULL);
110 container = gst_encoding_container_profile_new ("mp4", NULL, caps, NULL);
111 gst_caps_unref (caps);
112
113 caps = gst_caps_new_empty_simple ("video/x-h264");
114 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
115 gst_encoding_video_profile_new (caps, NULL, NULL, 1));
116 gst_caps_unref (caps);
117
118 caps = gst_caps_new_simple ("audio/mpeg", "version", G_TYPE_INT, 4, NULL);
119 gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *)
120 gst_encoding_audio_profile_new (caps, NULL, NULL, 1));
121 gst_caps_unref (caps);
122
123 return (GstEncodingProfile *) container;
124 }
125
126 GstCameraVideoFormat formats[] = {
127 {"ogg (theora/vorbis)", create_ogg_profile}
128 ,
129 {"webm (vp8/vorbis)", create_webm_profile}
130 ,
131 {"mp4 (h264+aac)", create_mp4_profile}
132 ,
133 {NULL, NULL}
134 };
135
136 void
on_mainWindow_delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)137 on_mainWindow_delete_event (GtkWidget * widget, GdkEvent * event, gpointer data)
138 {
139 gtk_main_quit ();
140 }
141
142 void
on_captureButton_clicked(GtkButton * button,gpointer user_data)143 on_captureButton_clicked (GtkButton * button, gpointer user_data)
144 {
145 g_signal_emit_by_name (camera, "start-capture", NULL);
146 }
147
148 void
on_stopCaptureButton_clicked(GtkButton * button,gpointer user_data)149 on_stopCaptureButton_clicked (GtkButton * button, gpointer user_data)
150 {
151 g_signal_emit_by_name (camera, "stop-capture", NULL);
152 }
153
154 void
on_imageRButton_toggled(GtkToggleButton * button,gpointer user_data)155 on_imageRButton_toggled (GtkToggleButton * button, gpointer user_data)
156 {
157 if (gtk_toggle_button_get_active (button)) {
158 g_object_set (camera, "mode", 1, NULL); /* Image mode */
159 }
160 }
161
162 void
on_videoRButton_toggled(GtkToggleButton * button,gpointer user_data)163 on_videoRButton_toggled (GtkToggleButton * button, gpointer user_data)
164 {
165 if (gtk_toggle_button_get_active (button)) {
166 g_object_set (camera, "mode", 2, NULL); /* Video mode */
167 }
168 }
169
170 void
on_viewfinderArea_realize(GtkWidget * widget,gpointer data)171 on_viewfinderArea_realize (GtkWidget * widget, gpointer data)
172 {
173 gdk_window_ensure_native (gtk_widget_get_window (widget));
174 }
175
176 void
on_formatComboBox_changed(GtkWidget * widget,gpointer data)177 on_formatComboBox_changed (GtkWidget * widget, gpointer data)
178 {
179 GstEncodingProfile *profile = NULL;
180 gint index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
181
182 if (formats[index].create_profile) {
183 profile = formats[index].create_profile ();
184 }
185
186 g_return_if_fail (profile != NULL);
187 gst_element_set_state (camera, GST_STATE_NULL);
188 g_object_set (camera, "video-profile", profile, NULL);
189 gst_encoding_profile_unref (profile);
190
191 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (camera,
192 GST_STATE_PLAYING)) {
193 GtkWidget *dialog =
194 gtk_message_dialog_new (GTK_WINDOW (ui_main_window), GTK_DIALOG_MODAL,
195 GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
196 "Could not initialize camerabin with the "
197 "selected format. Your system might not have the required plugins installed.\n"
198 "Please select another format.");
199
200 gtk_dialog_run (GTK_DIALOG (dialog));
201
202 gtk_widget_destroy (dialog);
203 }
204 }
205
206 void
on_zoomScale_value_changed(GtkWidget * widget,gpointer data)207 on_zoomScale_value_changed (GtkWidget * widget, gpointer data)
208 {
209 g_object_set (camera, "zoom",
210 (gfloat) gtk_range_get_value (GTK_RANGE (widget)), NULL);
211 }
212
213 static GstBusSyncReply
bus_sync_callback(GstBus * bus,GstMessage * message,gpointer data)214 bus_sync_callback (GstBus * bus, GstMessage * message, gpointer data)
215 {
216 GtkWidget *ui_drawing;
217
218 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
219 return GST_BUS_PASS;
220
221 if (!gst_message_has_name (message, "prepare-window-handle"))
222 return GST_BUS_PASS;
223
224 /* FIXME: make sure to get XID in main thread */
225 ui_drawing = GTK_WIDGET (gtk_builder_get_object (builder, "viewfinderArea"));
226 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (message->src),
227 GDK_WINDOW_XID (gtk_widget_get_window (ui_drawing)));
228
229 gst_message_unref (message);
230 return GST_BUS_DROP;
231 }
232
233
234 static gboolean
bus_callback(GstBus * bus,GstMessage * message,gpointer data)235 bus_callback (GstBus * bus, GstMessage * message, gpointer data)
236 {
237 switch (GST_MESSAGE_TYPE (message)) {
238 case GST_MESSAGE_WARNING:{
239 GError *err;
240 gchar *debug;
241
242 gst_message_parse_warning (message, &err, &debug);
243 g_print ("Warning: %s\n", err->message);
244 g_error_free (err);
245 g_free (debug);
246 break;
247 }
248 case GST_MESSAGE_ERROR:{
249 GError *err = NULL;
250 gchar *debug = NULL;
251
252 gst_message_parse_error (message, &err, &debug);
253 g_print ("Error: %s : %s\n", err->message, debug);
254 g_error_free (err);
255 g_free (debug);
256
257 gtk_main_quit ();
258 break;
259 }
260 case GST_MESSAGE_EOS:
261 /* end-of-stream */
262 g_print ("Eos\n");
263 gtk_main_quit ();
264 break;
265 case GST_MESSAGE_ELEMENT:
266 {
267 //handle_element_message (message);
268 break;
269 }
270 default:
271 /* unhandled message */
272 break;
273 }
274 return TRUE;
275 }
276
277 static gboolean
init_gtkwidgets_data(void)278 init_gtkwidgets_data (void)
279 {
280 gint i;
281 GtkComboBoxText *combobox =
282 GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, "formatComboBox"));
283
284 /* init formats combobox */
285 i = 0;
286 while (formats[i].name) {
287 gtk_combo_box_text_append_text (combobox, formats[i].name);
288 i++;
289 }
290
291 /* default to the first one -> ogg */
292 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0);
293 return TRUE;
294 }
295
296 int
main(int argc,char * argv[])297 main (int argc, char *argv[])
298 {
299 GError *error = NULL;
300 GstBus *bus;
301
302 /* FIXME: add support for Gdk Wayland backend, code currently assumes X11 */
303 if (g_getenv ("GDK_BACKEND") == NULL)
304 g_setenv ("GDK_BACKEND", "x11", TRUE);
305
306 gst_init (&argc, &argv);
307 gtk_init (&argc, &argv);
308
309 builder = gtk_builder_new ();
310 if (!gtk_builder_add_from_file (builder, UI_FILE, &error)) {
311 g_warning ("Error: %s", error->message);
312 g_error_free (error);
313 return 1;
314 }
315
316 camera = gst_element_factory_make ("camerabin", "camera");
317 bus = gst_pipeline_get_bus (GST_PIPELINE (camera));
318 gst_bus_add_watch (bus, bus_callback, NULL);
319 gst_bus_set_sync_handler (bus, bus_sync_callback, NULL, NULL);
320 gst_object_unref (bus);
321
322 if (!init_gtkwidgets_data ()) {
323 goto error;
324 }
325
326 ui_main_window = GTK_WIDGET (gtk_builder_get_object (builder, "mainWindow"));
327 gtk_builder_connect_signals (builder, NULL);
328 gtk_widget_show_all (ui_main_window);
329
330 gst_element_set_state (camera, GST_STATE_PLAYING);
331
332 gtk_main ();
333
334 error:
335 gst_element_set_state (camera, GST_STATE_NULL);
336 gst_object_unref (camera);
337 return 0;
338 }
339