1 #include <gst/gst.h>
2 #include <gtk/gtk.h>
3 #include <gdk/gdkx.h>
4 #include <gst/video/video.h>
5
6 #define WINDOW_GLADE "window.glade"
7 #define INT_PROPERTY_GLADE "int_property.glade"
8 #define ENUM_PROPERTY_GLADE "enum_property.glade"
9 #define BOOL_PROPERTY_GLADE "boolean_property.glade"
10
11 #define PROPERTY_TO_VBOX \
12 properties[i].dynamic ? GTK_BOX (dynamic_vbox) : GTK_BOX (static_vbox)
13
14 #define GET_WIDGET(object, type, name) \
15 type (gtk_builder_get_object ((object)->builder, name))
16
17 #define GET_PROP_WIDGET(type, name) GET_WIDGET (&(properties[i]), type, name)
18
19 static guint h264_xid, preview_xid;
20
21 typedef struct
22 {
23 GtkBuilder *builder;
24 GstElement *src;
25 enum
26 { NONE, INT, ENUM, BOOL } type;
27 const gchar *property_name;
28 gboolean readonly;
29 gboolean dynamic;
30 } Prop;
31
32 typedef struct
33 {
34 GtkBuilder *builder;
35 GstElement *bin;
36 GstElement *src;
37 GstElement *identity;
38 GstElement *vid_capsfilter;
39 GstElement *vf_capsfilter;
40 } Main;
41
42 Prop properties[] = {
43 {NULL, NULL, INT, "initial-bitrate", FALSE, FALSE},
44 {NULL, NULL, INT, "slice-units", FALSE, FALSE},
45 {NULL, NULL, ENUM, "slice-mode", FALSE, FALSE},
46 {NULL, NULL, INT, "iframe-period", FALSE, FALSE},
47 {NULL, NULL, ENUM, "usage-type", FALSE, FALSE},
48 {NULL, NULL, ENUM, "entropy", FALSE, FALSE},
49 {NULL, NULL, BOOL, "enable-sei", FALSE, FALSE},
50 {NULL, NULL, INT, "num-reorder-frames", FALSE, FALSE},
51 {NULL, NULL, BOOL, "preview-flipped", FALSE, FALSE},
52 {NULL, NULL, INT, "leaky-bucket-size", FALSE, FALSE},
53 {NULL, NULL, INT, "num-clock-samples", FALSE, TRUE},
54 {NULL, NULL, ENUM, "rate-control", FALSE, TRUE},
55 {NULL, NULL, BOOL, "fixed-framerate", FALSE, TRUE},
56 {NULL, NULL, INT, "max-mbps", TRUE, TRUE},
57 {NULL, NULL, INT, "level-idc", FALSE, TRUE},
58 {NULL, NULL, INT, "peak-bitrate", FALSE, TRUE},
59 {NULL, NULL, INT, "average-bitrate", FALSE, TRUE},
60 {NULL, NULL, INT, "min-iframe-qp", FALSE, TRUE},
61 {NULL, NULL, INT, "max-iframe-qp", FALSE, TRUE},
62 {NULL, NULL, INT, "min-pframe-qp", FALSE, TRUE},
63 {NULL, NULL, INT, "max-pframe-qp", FALSE, TRUE},
64 {NULL, NULL, INT, "min-bframe-qp", FALSE, TRUE},
65 {NULL, NULL, INT, "max-bframe-qp", FALSE, TRUE},
66 {NULL, NULL, INT, "ltr-buffer-size", FALSE, TRUE},
67 {NULL, NULL, INT, "ltr-encoder-control", FALSE, TRUE},
68 };
69
70 static void set_drop_probability (Main * self);
71 static void get_all_properties (void);
72 static void probe_all_properties (gboolean playing);
73
74 /* Callbacks */
75 void on_button_toggled (GtkToggleButton * button, gpointer user_data);
76 void on_get_button_clicked (GtkButton * button, gpointer user_data);
77 void on_set_button_clicked (GtkButton * button, gpointer user_data);
78 void on_button_ready_clicked (GtkButton * button, gpointer user_data);
79 void on_button_null_clicked (GtkButton * button, gpointer user_data);
80 void on_button_playing_clicked (GtkButton * button, gpointer user_data);
81 void on_iframe_button_clicked (GtkButton * button, gpointer user_data);
82 void on_renegotiate_button_clicked (GtkButton * button, gpointer user_data);
83 void on_start_capture_button_clicked (GtkButton * button, gpointer user_data);
84 void on_stop_capture_button_clicked (GtkButton * button, gpointer user_data);
85 void on_window_destroyed (GtkWindow * window, gpointer user_data);
86
87 static GstEvent *
new_upstream_force_key_unit(GstClockTime running_time,gboolean all_headers,guint count)88 new_upstream_force_key_unit (GstClockTime running_time,
89 gboolean all_headers, guint count)
90 {
91 GstEvent *force_key_unit_event;
92 GstStructure *s;
93
94 s = gst_structure_new ("GstForceKeyUnit",
95 "running-time", GST_TYPE_CLOCK_TIME, running_time,
96 "all-headers", G_TYPE_BOOLEAN, all_headers,
97 "count", G_TYPE_UINT, count, NULL);
98 force_key_unit_event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, s);
99
100 return force_key_unit_event;
101 }
102
103 void
on_get_button_clicked(GtkButton * button,gpointer user_data)104 on_get_button_clicked (GtkButton * button, gpointer user_data)
105 {
106 Prop *property = user_data;
107
108 switch (property->type) {
109 case INT:
110 {
111 gchar *val;
112 gint val_int;
113 g_object_get (property->src, property->property_name, &val_int, NULL);
114 val = g_strdup_printf ("%d", val_int);
115 gtk_entry_set_text (GET_WIDGET (property, GTK_ENTRY, "value"), val);
116 g_free (val);
117 }
118 break;
119 case ENUM:
120 {
121 GParamSpec *param;
122 gint val;
123
124 g_object_get (property->src, property->property_name, &val, NULL);
125 param = g_object_class_find_property (G_OBJECT_GET_CLASS (property->src),
126 property->property_name);
127 if (G_IS_PARAM_SPEC_ENUM (param)) {
128 GEnumValue *values;
129 guint i = 0;
130
131 values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
132
133 while (values[i].value_name) {
134 if (values[i].value == val) {
135 gtk_combo_box_set_active (GET_WIDGET (property,
136 (GtkComboBox *), "value"), i);
137 break;
138 }
139 i++;
140 }
141 }
142 }
143 break;
144 case BOOL:
145 {
146 gboolean val;
147
148 g_object_get (property->src, property->property_name, &val, NULL);
149 gtk_toggle_button_set_active (GET_WIDGET (property,
150 (GtkToggleButton *), "value"), val);
151 }
152 break;
153 case NONE:
154 default:
155 break;
156 }
157 }
158
159 void
on_set_button_clicked(GtkButton * button,gpointer user_data)160 on_set_button_clicked (GtkButton * button, gpointer user_data)
161 {
162 Prop *property = user_data;
163
164 switch (property->type) {
165 case INT:
166 {
167 int val_int;
168 const gchar *val;
169
170 val = gtk_entry_get_text (GET_WIDGET (property, GTK_ENTRY, "value"));
171 val_int = (int) g_ascii_strtoll (val, NULL, 0);
172 g_object_set (property->src, property->property_name, val_int, NULL);
173 }
174 break;
175 case ENUM:
176 {
177 GParamSpec *param;
178
179 param = g_object_class_find_property (G_OBJECT_GET_CLASS (property->src),
180 property->property_name);
181 if (G_IS_PARAM_SPEC_ENUM (param)) {
182 GEnumValue *values;
183 guint val = 0;
184
185 values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
186
187 val = gtk_combo_box_get_active (GET_WIDGET (property,
188 (GtkComboBox *), "value"));
189 g_object_set (property->src, property->property_name,
190 values[val].value, NULL);
191 }
192 }
193 break;
194 case BOOL:
195 {
196 gboolean val;
197
198 val = gtk_toggle_button_get_active (GET_WIDGET (property,
199 (GtkToggleButton *), "value"));
200 g_object_set (property->src, property->property_name, val, NULL);
201 }
202 break;
203 case NONE:
204 default:
205 break;
206 }
207 get_all_properties ();
208 }
209
210 void
on_button_toggled(GtkToggleButton * button,gpointer user_data)211 on_button_toggled (GtkToggleButton * button, gpointer user_data)
212 {
213 if (gtk_toggle_button_get_active (button))
214 gtk_button_set_label (GTK_BUTTON (button), " Enabled ");
215 else
216 gtk_button_set_label (GTK_BUTTON (button), " Disabled ");
217 }
218
219 static gboolean
set_caps(Main * self,gboolean send_event)220 set_caps (Main * self, gboolean send_event)
221 {
222 const gchar *h264_filter;
223 const gchar *raw_filter;
224 GstCaps *h264_caps = NULL;
225 GstCaps *raw_caps = NULL;
226 gboolean ret = TRUE;
227
228 h264_filter = gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "h264_caps"));
229 raw_filter =
230 gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "preview_caps"));
231 if (h264_filter)
232 h264_caps = gst_caps_from_string (h264_filter);
233 if (raw_filter)
234 raw_caps = gst_caps_from_string (raw_filter);
235
236 g_debug ("H264 caps : %s", gst_caps_to_string (h264_caps));
237 g_debug ("Preview caps : %s", gst_caps_to_string (raw_caps));
238 if (!h264_caps || !raw_caps) {
239 g_debug ("Invalid caps");
240 ret = FALSE;
241 goto end;
242 }
243
244 g_object_set (self->vid_capsfilter, "caps", h264_caps, NULL);
245 g_object_set (self->vf_capsfilter, "caps", raw_caps, NULL);
246
247 if (send_event) {
248 gst_element_send_event (GST_ELEMENT (self->src),
249 gst_event_new_reconfigure ());
250 }
251
252 end:
253 if (h264_caps)
254 gst_caps_unref (h264_caps);
255 if (raw_caps)
256 gst_caps_unref (raw_caps);
257
258 return ret;
259 }
260
261 void
on_button_ready_clicked(GtkButton * button,gpointer user_data)262 on_button_ready_clicked (GtkButton * button, gpointer user_data)
263 {
264 Main *self = user_data;
265
266 set_caps (self, FALSE);
267 gst_element_set_state (self->bin, GST_STATE_READY);
268 probe_all_properties (FALSE);
269 get_all_properties ();
270 }
271
272 void
on_button_null_clicked(GtkButton * button,gpointer user_data)273 on_button_null_clicked (GtkButton * button, gpointer user_data)
274 {
275 Main *self = user_data;
276
277 gst_element_set_state (self->bin, GST_STATE_NULL);
278 probe_all_properties (FALSE);
279 get_all_properties ();
280 }
281
282 void
on_button_playing_clicked(GtkButton * button,gpointer user_data)283 on_button_playing_clicked (GtkButton * button, gpointer user_data)
284 {
285 Main *self = user_data;
286
287 if (gst_element_set_state (self->bin, GST_STATE_PLAYING) ==
288 GST_STATE_CHANGE_FAILURE) {
289 g_debug ("Unable to go to state PLAYING");
290 }
291 set_caps (self, FALSE);
292 probe_all_properties (TRUE);
293 get_all_properties ();
294
295 set_drop_probability (self);
296 }
297
298 void
on_iframe_button_clicked(GtkButton * button,gpointer user_data)299 on_iframe_button_clicked (GtkButton * button, gpointer user_data)
300 {
301 Main *self = user_data;
302 GstEvent *event;
303 gboolean pps_sps;
304
305 set_drop_probability (self);
306 pps_sps = gtk_toggle_button_get_active (GET_WIDGET (self, (GtkToggleButton *),
307 "pps_sps"));
308
309 event = new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, pps_sps, 0);
310 gst_element_send_event (GST_ELEMENT (self->src), event);
311 }
312
313 void
on_renegotiate_button_clicked(GtkButton * button,gpointer user_data)314 on_renegotiate_button_clicked (GtkButton * button, gpointer user_data)
315 {
316 Main *self = user_data;
317
318 set_caps (self, TRUE);
319 probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED);
320 get_all_properties ();
321 }
322
323 void
on_start_capture_button_clicked(GtkButton * button,gpointer user_data)324 on_start_capture_button_clicked (GtkButton * button, gpointer user_data)
325 {
326 Main *self = user_data;
327
328 set_caps (self, FALSE);
329 g_signal_emit_by_name (G_OBJECT (self->src), "start-capture", NULL);
330 probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED);
331 get_all_properties ();
332 }
333
334 void
on_stop_capture_button_clicked(GtkButton * button,gpointer user_data)335 on_stop_capture_button_clicked (GtkButton * button, gpointer user_data)
336 {
337 Main *self = user_data;
338
339 set_caps (self, FALSE);
340 g_signal_emit_by_name (G_OBJECT (self->src), "stop-capture", NULL);
341 probe_all_properties (GST_STATE (self->bin) >= GST_STATE_PAUSED);
342 get_all_properties ();
343 }
344
345 void
on_window_destroyed(GtkWindow * window,gpointer user_data)346 on_window_destroyed (GtkWindow * window, gpointer user_data)
347 {
348 gtk_main_quit ();
349 }
350
351 static gboolean
_bus_callback(GstBus * bus,GstMessage * message,gpointer user_data)352 _bus_callback (GstBus * bus, GstMessage * message, gpointer user_data)
353 {
354 const GstStructure *s = gst_message_get_structure (message);
355 GstObject *source = NULL;
356
357 if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT &&
358 gst_structure_has_name (s, "prepare-window-handle")) {
359 source = GST_MESSAGE_SRC (message);
360 if (!g_strcmp0 (gst_object_get_name (source), "h264_sink"))
361 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (source),
362 h264_xid);
363 else
364 gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (source),
365 preview_xid);
366 }
367
368 return TRUE;
369 }
370
371 static void
set_drop_probability(Main * self)372 set_drop_probability (Main * self)
373 {
374 const gchar *drop;
375 gdouble drop_probability = 0.0;
376
377 drop = gtk_entry_get_text (GET_WIDGET (self, GTK_ENTRY, "drop"));
378 drop_probability = g_ascii_strtod (drop, NULL);
379 g_debug ("Setting drop probability to : %f", drop_probability);
380 g_object_set (self->identity, "drop-probability", drop_probability, NULL);
381 }
382
383 static void
get_all_properties(void)384 get_all_properties (void)
385 {
386 int i;
387
388 for (i = 0; i < G_N_ELEMENTS (properties); i++)
389 on_get_button_clicked (NULL, &properties[i]);
390
391 }
392
393 static void
probe_all_properties(gboolean playing)394 probe_all_properties (gboolean playing)
395 {
396 int i;
397
398 for (i = 0; i < G_N_ELEMENTS (properties); i++) {
399 gboolean return_value, changeable, default_bool;
400 guint mask, minimum, maximum, default_int;
401 GParamSpec *param;
402
403 /* When playing, ignore static controls */
404 if (playing && !properties[i].dynamic)
405 continue;
406
407 switch (properties[i].type) {
408 case INT:
409 g_signal_emit_by_name (G_OBJECT (properties[i].src), "get-int-setting",
410 properties[i].property_name, &minimum, &default_int, &maximum,
411 &return_value, NULL);
412 if (return_value) {
413 gchar *min, *def, *max;
414
415 min = g_strdup_printf ("%d", minimum);
416 def = g_strdup_printf ("%d", default_int);
417 max = g_strdup_printf ("%d", maximum);
418 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "minimum"), min);
419 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), def);
420 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "maximum"), max);
421 g_free (min);
422 g_free (def);
423 g_free (max);
424 } else {
425 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "minimum"), "");
426 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), "");
427 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "maximum"), "");
428 }
429 break;
430 case ENUM:
431 g_signal_emit_by_name (G_OBJECT (properties[i].src), "get-enum-setting",
432 properties[i].property_name, &mask, &default_int, &return_value,
433 NULL);
434 param =
435 g_object_class_find_property (G_OBJECT_GET_CLASS (properties
436 [i].src), properties[i].property_name);
437 if (G_IS_PARAM_SPEC_ENUM (param)) {
438 GEnumValue *values;
439 guint j = 0;
440
441 values = G_ENUM_CLASS (g_type_class_ref (param->value_type))->values;
442
443 if (return_value) {
444 while (values[j].value_name) {
445 if (values[j].value == default_int) {
446 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"),
447 values[j].value_name);
448 break;
449 }
450 j++;
451 }
452 } else {
453 gtk_entry_set_text (GET_PROP_WIDGET (GTK_ENTRY, "default"), "");
454 }
455
456 j = 0;
457 while (values[j].value_name) {
458 #if !GTK_CHECK_VERSION (2, 24, 0)
459 gtk_combo_box_remove_text (GET_PROP_WIDGET ((GtkComboBox *),
460 "value"), 0);
461 #else
462 gtk_combo_box_text_remove (GET_PROP_WIDGET ((GtkComboBoxText *),
463 "value"), 0);
464 #endif
465 j++;
466 }
467
468 j = 0;
469 while (values[j].value_name) {
470 gchar *val;
471 if (return_value && (mask & (1 << values[j].value)) != 0)
472 val = g_strdup_printf ("**%s**", values[j].value_name);
473 else
474 val = g_strdup (values[j].value_name);
475
476 #if !GTK_CHECK_VERSION (2, 24, 0)
477 gtk_combo_box_append_text (GET_PROP_WIDGET ((GtkComboBox *),
478 "value"), val);
479 #else
480 gtk_combo_box_text_append_text (GET_PROP_WIDGET ((GtkComboBoxText
481 *), "value"), val);
482 #endif
483 g_free (val);
484 j++;
485 }
486 }
487 break;
488 case BOOL:
489 g_signal_emit_by_name (G_OBJECT (properties[i].src),
490 "get-boolean-setting", properties[i].property_name,
491 &changeable, &default_bool, &return_value, NULL);
492 if (return_value) {
493 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "value"),
494 changeable);
495 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "get"),
496 changeable);
497 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"),
498 changeable);
499 gtk_toggle_button_set_active (GET_PROP_WIDGET ((GtkToggleButton *),
500 "default"), default_bool);
501 }
502 break;
503 case NONE:
504 default:
505 break;
506 }
507 }
508 }
509
510 int
main(int argc,char * argv[])511 main (int argc, char *argv[])
512 {
513 Main self = { NULL, NULL, NULL, NULL };
514 GstBus *bus = NULL;
515 GtkWidget *window, *static_vbox, *dynamic_vbox, *da;
516 gchar *drop;
517 gdouble drop_probability;
518 GdkWindow *gdk_win = NULL;
519 const char *device = "/dev/video0";
520 GError *error = NULL;
521 int i;
522
523 /* FIXME: add support for Gdk Wayland backend, code currently assumes X11 */
524 if (g_getenv ("GDK_BACKEND") == NULL)
525 g_setenv ("GDK_BACKEND", "x11", TRUE);
526
527 gtk_init (&argc, &argv);
528 gst_init (&argc, &argv);
529
530 if (argc > 1)
531 device = argv[1];
532 else
533 g_print ("Usage : %s [device]\nUsing default device : %s\n",
534 argv[0], device);
535
536
537 self.bin = gst_parse_launch ("uvch264src name=src src.vidsrc ! queue ! "
538 "capsfilter name=vid_cf ! identity name=identity ! decodebin ! "
539 "xvimagesink name=h264_sink async=false "
540 "src.vfsrc ! queue ! capsfilter name=vf_cf ! "
541 "xvimagesink name=preview_sink async=false", NULL);
542
543 if (!self.bin)
544 return -1;
545
546 /* Listen to the bus for messages */
547 bus = gst_element_get_bus (self.bin);
548 gst_bus_add_watch (bus, _bus_callback, self.bin);
549 gst_object_unref (bus);
550
551 self.src = gst_bin_get_by_name (GST_BIN (self.bin), "src");
552 self.identity = gst_bin_get_by_name (GST_BIN (self.bin), "identity");
553 self.vid_capsfilter = gst_bin_get_by_name (GST_BIN (self.bin), "vid_cf");
554 self.vf_capsfilter = gst_bin_get_by_name (GST_BIN (self.bin), "vf_cf");
555
556 self.builder = gtk_builder_new ();
557 gtk_builder_add_from_file (self.builder, WINDOW_GLADE, &error);
558 if (error) {
559 g_debug ("Unable to load glade file : %s", error->message);
560 goto end;
561 }
562 gtk_builder_connect_signals (self.builder, &self);
563
564 g_object_get (self.identity, "drop-probability", &drop_probability, NULL);
565 drop = g_strdup_printf ("%f", drop_probability);
566 gtk_entry_set_text (GET_WIDGET (&self, GTK_ENTRY, "drop"), drop);
567 g_free (drop);
568 window = GET_WIDGET (&self, GTK_WIDGET, "window");
569 static_vbox = GET_WIDGET (&self, GTK_WIDGET, "static");
570 dynamic_vbox = GET_WIDGET (&self, GTK_WIDGET, "dynamic");
571 da = GET_WIDGET (&self, GTK_WIDGET, "h264");
572 gtk_widget_realize (da);
573 gdk_win = gtk_widget_get_window (da);
574 h264_xid = GDK_WINDOW_XID (gdk_win);
575 da = GET_WIDGET (&self, GTK_WIDGET, "preview");
576 gtk_widget_realize (da);
577 gdk_win = gtk_widget_get_window (da);
578 preview_xid = GDK_WINDOW_XID (gdk_win);
579
580 set_caps (&self, FALSE);
581
582 g_object_set (self.src, "device", device, NULL);
583 if (gst_element_set_state (self.bin, GST_STATE_READY) ==
584 GST_STATE_CHANGE_FAILURE) {
585 g_debug ("Unable to go to state READY");
586 goto end;
587 }
588
589 for (i = 0; i < G_N_ELEMENTS (properties); i++) {
590 switch (properties[i].type) {
591 case INT:
592 properties[i].src = self.src;
593 properties[i].builder = gtk_builder_new ();
594 gtk_builder_add_from_file (properties[i].builder, INT_PROPERTY_GLADE,
595 NULL);
596 gtk_builder_connect_signals (properties[i].builder, &properties[i]);
597 gtk_box_pack_start (PROPERTY_TO_VBOX,
598 GET_PROP_WIDGET (GTK_WIDGET, "int-property"), TRUE, TRUE, 2);
599 gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"),
600 properties[i].property_name);
601 if (properties[i].readonly)
602 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE);
603 break;
604 case ENUM:
605 properties[i].src = self.src;
606 properties[i].builder = gtk_builder_new ();
607 #if !GTK_CHECK_VERSION (2, 24, 0)
608 gtk_builder_add_from_file (properties[i].builder,
609 "enum_property_gtk2.glade", NULL);
610 #else
611 gtk_builder_add_from_file (properties[i].builder, ENUM_PROPERTY_GLADE,
612 NULL);
613 #endif
614 gtk_builder_connect_signals (properties[i].builder, &properties[i]);
615 gtk_box_pack_start (PROPERTY_TO_VBOX,
616 GET_PROP_WIDGET (GTK_WIDGET, "enum-property"), TRUE, TRUE, 2);
617 gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"),
618 properties[i].property_name);
619 #if !GTK_CHECK_VERSION (2, 24, 0)
620 {
621 GtkComboBox *combo_box;
622 GtkCellRenderer *cell;
623 GtkListStore *store;
624
625 combo_box = GET_PROP_WIDGET ((GtkComboBox *), "value");
626 store = gtk_list_store_new (1, G_TYPE_STRING);
627 gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store));
628 g_object_unref (store);
629
630 cell = gtk_cell_renderer_text_new ();
631 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
632 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
633 "text", 0, NULL);
634 }
635 #endif
636 if (properties[i].readonly)
637 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE);
638 break;
639 case BOOL:
640 properties[i].src = self.src;
641 properties[i].builder = gtk_builder_new ();
642 gtk_builder_add_from_file (properties[i].builder, BOOL_PROPERTY_GLADE,
643 NULL);
644 gtk_builder_connect_signals (properties[i].builder, &properties[i]);
645 gtk_box_pack_start (PROPERTY_TO_VBOX,
646 GET_PROP_WIDGET (GTK_WIDGET, "boolean-property"), TRUE, TRUE, 2);
647 gtk_label_set_label (GET_PROP_WIDGET (GTK_LABEL, "label"),
648 properties[i].property_name);
649 if (properties[i].readonly)
650 gtk_widget_set_sensitive (GET_PROP_WIDGET (GTK_WIDGET, "set"), FALSE);
651 break;
652 case NONE:
653 default:
654 break;
655 }
656 }
657 probe_all_properties (FALSE);
658 get_all_properties ();
659
660 gtk_widget_show (window);
661 gtk_main ();
662
663 end:
664 g_object_unref (G_OBJECT (self.builder));
665 for (i = 0; i < G_N_ELEMENTS (properties); i++) {
666 if (properties[i].builder)
667 g_object_unref (G_OBJECT (properties[i].builder));
668 }
669 gst_element_set_state (self.bin, GST_STATE_NULL);
670 gst_object_unref (self.src);
671 gst_object_unref (self.identity);
672 gst_object_unref (self.vid_capsfilter);
673 gst_object_unref (self.vf_capsfilter);
674 gst_object_unref (self.bin);
675
676 return 0;
677 }
678